I'm having trouble with event driven input detection for moving my actors.
I'm currently using a GestureDetector and detecting a Tap (this all works)`
#Override
public void show() {
GestureDetector GD = new GestureDetector(this);
InputMultiplexer inputMulti = new InputMultiplexer();
inputMulti.addProcessor(hudStage);
inputMulti.addProcessor(GD);
Gdx.input.setInputProcessor(inputMulti);
}
#Override
public boolean tap(float x, float y, int count, int button) {
System.out.println("YOU HAVE PERFORMED A TAP");
this.playStage.act(Gdx.graphics.getDeltaTime());
return true;
}`
Currently tap just prints out something along the lines of you have performed a tap(see above) it also calls the stage act method which works partly (It moves the actor a frames worth of movement instead of the entire distance). I've used polling to get the actor to perform how I want as i can call the method in the render loop which then allows it to continue updating movements frame by frame. Using Event driven I've not currently found a of updating it frame by frame so instead it does as much as it can in one frame and then stops.
I've looked around, a lot, looked into threading but it seems libgdx is not thread safe. My main problem with going back to polling is that i need to separate out my stages and I'm not entirely sure how to do that.
For polling i didn't use an action but used this code
if(!fStarted){
if (Gdx.input.isTouched()) {
fStarted = true;
touchX = Gdx.input.getX();
spriteX = cSprite.x;
}
}
final float dv = delta * speed;
if (Math.abs(touchX - spriteX) > 45) {
playStage.getBatch().draw(flameImage, spriteX, fSprite.y);
if (spriteX < touchX) {
spriteX += dv;
//fSprite.x = spriteX;
}
if (spriteX > touchX) {
spriteX -= dv;
//fSprite.x = spriteX;
}
}
else{
spriteX = 9000;
fStarted=false;
}
fStarted just determines whether or not the actor is currently moving to a position. As the actor is a projectile I didn't want more than one at one point (game choices you know).
If there is any other information you need just comment and I'll provide it.
Clarity
How can I use event driven gesture detection to move an actor to a position that is tapped by the user?
Related
I am making a simple 3D multiplayer game. In the server side I'm making all the calculations for each client/player in-game based on player position and look direction (both should be updated from user input), and then I want to send all resulting triangles/polygons to the client in order to draw to the screen in each frame. I want the client to send to the server in each frame the buttons pressed on the keyboard (so if W and Space are held down, their flags are set to true and sent that way to the server), and also the change in mouse position. Based on that input I change the position of the player in server-side and the look direction of the camera. The way I have it set up now is that both the client and server are infinite loops without delay.
The server goes something like this in each frame/iteration of the loop:
Send a message to client that tells it to update mouse (more about that below)
Double player speed for the frame if a specific key is pressed
Update look direction based of dx and dy (how much the mouse moved since last frame)
Calculate next position of player based on which keys are pressed
Collision detection, push back player if inside an object or wall
Project all scene triangles into 2D based on look direction (camera matrix)
Send a message to client that tells it to clear all triangles from list
Send the data of each 2D-projected triangle (coordinates and color)
And the client does this in each frame:
Send which keys are currently pressed and which are not
Call repaint() method:
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
ArrayList<Triangle> trianglesToDraw = new ArrayList<>(updatedTriangles);
trianglesToDraw.removeIf(Objects::isNull);
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
for (Triangle t : trianglesToDraw)
{
g.setColor(t.color);
int[] xValues = {(int) t.points[0].x, (int) t.points[1].x, (int) t.points[2].x};
int[] yValues = {(int) t.points[0].y, (int) t.points[1].y, (int) t.points[2].y};
g.fillPolygon(new Polygon(xValues, yValues, 3));
}
}
It is worth noting that each side has a separate thread which is responsible for handling messages from the other.
In the server side:
public void handleClientMessage(String message)
{
if (message.startsWith("keys: "))
{
String[] keyInfo = message.replaceAll(",", "").split(" ");
for (int i = 0; i < keysPressed.length; i++)
{
keysPressed[i] = Boolean.parseBoolean(keyInfo[i + 1]);
}
}
else if (message.startsWith("mouse_update: "))
{
String[] mouseInfo = message.split(" ");
try
{
mouseDX = Float.parseFloat(mouseInfo[1]);
mouseDY = Float.parseFloat(mouseInfo[2]);
}
catch (NumberFormatException e)
{
mouseDX = 0;
mouseDY = 0;
}
}
In the client side:
public void handleMessageFromServer(String message) throws IOException
{
if (message.contains("Update Mouse"))
{
mousePosition = MouseInfo.getPointerInfo().getLocation();
int centerX = screenWidth / 2;
int centerY = screenHeight / 2;
robot.mouseMove(centerX, centerY);
float dx = mousePosition.x - centerX;
float dy = mousePosition.y - centerY;
sendMessage("mouse_update: " + dx + " " + dy);
}
else if (message.equals("clear triangles"))
{
updatedTriangles.clear();
}
else if (message.startsWith("triangle"))
{
String[] triangleInfo = message.split(" ");
Triangle t = new Triangle(
new Vector(Float.parseFloat(triangleInfo[1]), Float.parseFloat(triangleInfo[2]), Float.parseFloat(triangleInfo[3])),
new Vector(Float.parseFloat(triangleInfo[4]), Float.parseFloat(triangleInfo[5]), Float.parseFloat(triangleInfo[6])),
new Vector(Float.parseFloat(triangleInfo[7]), Float.parseFloat(triangleInfo[8]), Float.parseFloat(triangleInfo[9])),
new Color(Integer.parseInt(triangleInfo[10]), Integer.parseInt(triangleInfo[11]), Integer.parseInt(triangleInfo[12]))
);
updatedTriangles.add(t);
}
}
Now my layout is really bad for many reasons:
I can barely move the camera because I expect the client to send updated dx and dy and the server to receive it and update it before it makes the new look direction calculation (which is really unrealistic considering the calculation happends only 2-3 O(1) calculations after the original request it sends to the client). What actually happens is that it's almost always 0.0 for both because it won't update in time.
The screen keeps flickering because the client isn't synced with the server so it updates the screen without receiving all triangles from the server and clears the screen before.
All of the important calculations are performed in server-side, which is something that makes sense in my mind, but it also means that the more clients there will be the slower it will run for everyone since the server has limited resources to calculate everything.
There are probably more problems that I can't think about at the moment but these are the main ones.
Anyways, I need help to figure out a better layout that will at the very least solve some of these problems and prevent some more future ones. I just don't have enough experience with this so I don't really know the best practices in server-client programming.
I'm attempting to create a game in unity, but Java isn't able to be used in it, so any premade scripts are in C#. I want to add some stuff in the mechanics of the game, which requires me to alter variables and values in the script, but I only know how to do so in java, so how would I make it so they can effectively communicate?
An example from c#:
protected override void ComputeVelocity()
{
Vector2 move = Vector2.zero;
move.x = Input.GetAxis ("Horizontal");
if (Input.GetButtonDown ("Jump") && grounded) {
velocity.y = jumpTakeOffSpeed;
} else if (Input.GetButtonUp ("Jump"))
{
if (velocity.y > 0)
velocity.y = velocity.y * .5f;
}
targetVelocity = move * maxSpeed;
}
}
and my java code:
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_SHIFT)
{
endTime = (System.currentTimeMillis() / 1000);
timePassed = endTime - startTime;
if(timePassed >= 2)
{
//try to set a time limit or something
velocity = overMaxVelocity;
//set velocity to above usual max for dodgeTime
startTime = dodgeTime + (System.currentTimeMillis() / 1000);
}
}
}
I'm trying to make it so when shift is pressed, the velocity is changed to a larger value than usual for a small time, but i have no idea where to even begin
Unity only supports scripts written in C#. It used to also support a version of JavaScript they called UnityScript, but they moved to only officially support C# now. Fortunately C# is really similar to Java, so you shouldn't have too much trouble translating your scripts to C#. The main challenge would be learning the Unity library.
I wrote some code below that updates an object's speed using Unity library functions. Unity has a lot of built-in ways of helping you out as a developer so I'd recommend the tutorials on Unity's website for more on getting started with it.
public float speed = 2;
public float speedUpFactor = 2;
// Get the Rigidbody component attached to this gameobject
// The rigidbody component is necessary for any object to use physics)
// This gameobject and any colliding gameobjects will also need collider components
Rigidbody rb;
// Start() gets called the first frame that this object is active (before Update)
public void Start(){
// save a reference to the rigidbody on this object
rb = GetComponent<Rigidbody>();
}
}// Update() gets called every frame, so you can check for input here.
public void Update() {
// Input.GetAxis("...") uses input defined in the "Edit/Project Settings/Input" window in the Unity editor.
// This will allow you to use the xbox 360 controllers by default, "wasd", and the arrow keys.
// Input.GetAxis("...") returns a float between -1 and 1
Vector3 moveForce = new Vector3(Input.GetAxis ("Horizontal"), 0, Input.GetAxis("Vertical"));
moveForce *= speed;
// Input.GetKey() returns true while the specified key is held down
// Input.GetKeyDown() returns true during the frame the key is pressed down
// Input.GetKeyUp() returns true during the frame the key is released
if(Input.GetKey(KeyCode.Shift))
{
moveForce *= speedUpFactor;
}
// apply the moveForce to the object
rb.AddForce(moveForce);
}
I'm trying to make a simple action in a Java FX "game" in which an image of a pig 'jumps' upwards every time the spacebar is pressed. Here is the code for the key event handlers and the Animation Timer that I'm using to actually carry out the action.
Key Handlers:
ArrayList<String> in = new ArrayList<String>();
s.setOnKeyPressed(
new EventHandler<KeyEvent>()
{
public void handle(KeyEvent e)
{
String code = e.getCode().toString();
if ( !in.contains(code) ){
in.add( code );
}
}
});
s.setOnKeyReleased(
new EventHandler<KeyEvent>()
{
public void handle(KeyEvent e)
{
String code = e.getCode().toString();
in.remove( code );
}
});
Animation timer:
new AnimationTimer()
{
double q = 200;
public void handle(long currentNanoTime)
{
double t = (currentNanoTime - startNanoTime) / 4000000.0;
if(in.contains("SPACE")){
q -= 20;
}
double y = q + t;
if(y >= 520){
gc.drawImage(background1, 0, 0, 1160, 740);
gc.drawImage(pig, 90, 520, 125, 100);
}else{
gc.drawImage(background1, 0, 0, 1160, 740);
gc.drawImage(pig, 90, y, 125, 100);
}
}
}.start();
So as you can see I'm having the animation timer simply cause the 'pig' to gradually fall down the y-axis, and when the spacebar is pressed, it is given a slight boost upwards.
The problem is that if the spacebar is held down, the pig just flies continuously upwards without stopping. I want this to be prevented so that the spacebar must be repeatedly tapped and not just held down. So I want only one 'jump' per spacebar press. Nothing that I've tried to workaround it has worked. How can I do this?
EDIT: I reworked the answer. The original solution used a counter which prevented the pressed key from having any impact for a certain period of time. Unfortunately, this was not what this question was about. :) The current solution is more straight forward and uses only a simple boolean lock.
Before answering the question, here are some annoying tips: I would suggest to use Map<KeyCode, Boolean> instead of List<String> to store information about what keys are currently pressed. It will simplify your code in terms of readability and give it a performance boost at the same time. Next, creating a dedicated object to store information about the pig (haha!) might be a good idea. Finally, using constants instead of hard coded literal values is a good practice.
Also, note that you don't actually need to store information about whether the spacebar is pressed or not and then refer to it from the timer thread. This would only be necessary if you WANTED the pig to be controlled by HOLDING the spacebar. But since you want it to jump only when the spacebar is pressed, you could tell the pig to switch into "jump" state directly from the handler. Of course, this won't solve your problem, because the onKeyPressed handler is invoked repeatedly when holding a key for a longer period of time. But I thought it was worth mentioning. :)
Now, to answer the question. If you want to quickfix your current solution and ignore all the "good practice" crap, focus only on the jumpLock field of the Pig class. The trick is to keep telling the pig to jump repeatedly as you are currently doing, BUT making sure that the pig will obey only when the jumpLock allows it to do so.
NOTE: The following solution assumes you will update the state of your game using a fixed interval like every 30 milliseconds. But as noted at the end, this solution can be easily modified to use FPS based timer.
The following class contains constants which you may want to change when tweaking your game in the future:
public final class Settings {
private Settings() {
}
public static final double BOOST_VELOCITY = 10.0;
public static final double GRAVITY = 0.3;
}
This class represents the pig. The x and y fields store information about current position of the pig. velocityX and velocityY are vectors containing information about the direction and "speed" of the pig in X and Y axis, respectively. jumpLock is a simple boolean flag which is actually a solution to your problem. Whenever user makes a jump, this lock is set to true. And it will remain so until it will be told to release the lock, which will happen when user releases the spacebar.
public final class Pig {
private double x;
private double y;
private double velocityX;
private double velocityY;
private boolean jumpLock;
public Pig() {
// ...
}
public void timeChanged() {
x += velocityX;
y += velocityY;
velocityY -= Settings.GRAVITY;
}
public void jumpBoost() {
if (!jumpLock) {
velocityY = Settings.BOOST_VELOCITY;
jumpLock = true;
}
}
public void releaseLock() {
jumpLock = false;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
Your handlers could look like this. Notice that Map<KeyCode, Boolean> is used to store information about currently pressed keys. It performs better than List<String> in this situation. Also adding the #Override annotation is a good practice even when overriding methods which are abstract:
final Map<KeyCode, Boolean> keyboard = new HashMap<>();
keyboard.put(KeyCode.SPACE, false);
scene.setOnKeyPressed(
new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.SPACE) {
keyboard.put(e.getCode(), true);
// You could alternately call pig.jumpBoost()
// directly from this handler and not having to
// deal with the 'keyboard' map at all
// as illustrated with by pig.releaseLock()
// in the next handler
}
}
});
scene.setOnKeyReleased(
new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.SPACE) {
keyboard.put(e.getCode(), false);
pig.releaseLock(); // IMPORTANT!!!
}
}
});
Finally, the following snippet of code must be executed repeatedly. This solution assumes this code will be executed in a fixed interval like every 30 milliseconds. If you are using FPS based timer (meaning there will be irregular interval between executions), you should pass the time which elapsed from the previous update as a parameter to the timeChanged() method, and multiply with it whatever necessary inside that method.
pig.timeChanged();
if (keyboard.get(KeyCode.SPACE)) {
pig.jumpBoost();
}
// Note that pig.releaseLock() could be called in else
// branch here and not in the onKeyReleased handler.
// Choose whatever solution suits you best.
// + draw image of the pig on pig.getX() and pig.getY() coordinates
Hope I got this right. I was almost asleep when writing this post and misunderstood the question at first. But I really need to earn some reputation points to be allowed to comment on an issue which is currently important to me. Haha! :D:D
I am working on a first person game in Java, and I am trying to get the 3D movement working.
My problem is I would like to capture mouse movement, yet keep the mouse inside the window. After I capture the mouse movement, I figure the best way to keep the mouse in my window is to center the mouse in the window after moving, using Robot.moveMouse(x,y). This works fine, however the movement from the Robot triggers an event in my window which then gets interpreted as a normal event, and thus moves my character in the world.
I've tried various schemes of keeping state and ignoring movements until I am in the center, but they all seem finicky and don't quite detect which events are user vs Robot controlled.
Is there an easy way to detect that a mouse movement came from the Robot?
Is there perhaps a simpler way to solve my problem that I am overlooking?
I solved this by switching to NEWT with JOGL 2.0 RC4. In particular, I use GLWindow and warpPointer instead of an AWT Frame with the Robot.mouseMove. With the switch, I instantly got smooth movements. Some sample code similar to what I'm doing (mileage may vary):
public class MyClass implements MouseListener {
private GLWindow window;
private int centeredX = -1;
private int centeredY = -1;
// ...
public void mouseMoved(MouseEvent e) {
if (centeredX == -1 || centeredY == -1) {
center();
return;
}
int deltaX = e.getX() - centeredX;
int deltaY = e.getY() - centeredY;
// ... Do something with the deltas
centeredX = window.getWidth() / 2;
centeredY = window.getHeight() / 2;
window.warpPointer(centeredX, centeredY);
}
}
Well, I'm not 100% about this, but have you used the getsource() or getComponent() functions on your mouse event? They may return the robot as the source of it. Barring that, I would have a class variable like boolean robotControlling and anytime it takes control of the mouse, set that to true. Then, in you mouseListener, do a if(!robotControlling){...}. Hope this helps.
EDIT: if you have unused mouse buttons in your application (Java has Button 1, Button 2 and Button 3), you could make the robot press that, and in your mouse listener ignore any events with that code pressed. (use evt.getButton() for this) Of course, thats not exactly the cleanest solution :P
I'm working on a pacman clone in java using eclipse and sometimes it appears laggy more specifically the movement of pacman/ghosts is slow, sometimes its fine. Once it has happened while I was running it so it wasn't after I added code and it doesn't seem to be after any specific event in game. I can't find any trigger or produce the lag on purpose
The resource manager shows the same cpu usage(only around 50%)/memory usage . Aswell the FPS seems to be around 200 consistently through lag and during the periods where it is working well.
Does anyone know what this could be?
Is there any information I left out that could be of use?
edit - I am basing movement on a timer is that bad? I will post the movement relevant code below is there a good way of posting the whole code on here?
Timer movement = new Timer(20, new ActionListener()//500 is time in milliseconds between
//calls to actionPerformed as far as I know.
{
public void actionPerformed(ActionEvent arg0)
{
if(movingUp == true)
{
moveUp();
}
else if(movingDown == true)
{
moveDown();
}
else if(movingRight == true)
{
moveRight();
}
else if(movingLeft == true)
{
moveLeft();
}
}
});
public void moveUp()
{
yPos -= 1;
this.rect.y -= 1;
}
public void setDirUp()
{
movingUp = true;
movingDown = false;
movingRight = false;
movingLeft = false;
}
in the main class in public void keyPressed:
if(keyCode == KeyEvent.VK_W)
{
if(pacMan.isUpHittingWall == false)
{
pacMan.setDirUp();
pacMan.isDownHittingWall = false;
pacMan.isRightHittingWall = false;
pacMan.isLeftHittingWall = false;
}
}
edit 2 -Thanks for the help guys. I have the movement using System time now and it seems to have fixed the issue because I implemented it only for pacman at first and the ghosts were still slow. Now there is an issue where moving right and down are much slower than moving left or up The only difference I see is that right and down are both adding and left and up are subtracting. What can I do about this?
The updated code is below.
//updated movement code
public void moveUp(long timePassed)
{
yPos -= vy * timePassed;
this.rect.y -= vy * timePassed;
}
public void moveDown(long timePassed)
{
yPos += vy * timePassed;
this.rect.y += vy * timePassed;
}
public void moveRight(long timePassed)
{
xPos += vx * timePassed;
this.rect.x += vx * timePassed;
}
public void moveLeft(long timePassed)
{
xPos -= vx * timePassed;
this.rect.x -= vx * timePassed;
}
//I passed timePassed through a globalInputObject because my input is handled in public //void keyPressed(KeyEvent e) and I didnt know how else to get timePassed in to the //movement method
//Here is the code in gameLoop()
globalInputObject.isPacManMovingUp(timePassed);
globalInputObject.isPacManMovingDown(timePassed);
globalInputObject.isPacManMovingRight(timePassed);
globalInputObject.isPacManMovingLeft(timePassed);
//This is inside the GlobalInputObject
public void isPacManMovingUp(long timePassed)
{
if(pacMan.movingUp == true)
{
pacMan.moveUp(timePassed);
}
}
public void isPacManMovingDown(long timePassed)
{
if(pacMan.movingDown == true)
{
pacMan.moveDown(timePassed);
}
}
public void isPacManMovingRight(long timePassed)
{
if(pacMan.movingRight == true)
{
pacMan.moveRight(timePassed);
}
}
public void isPacManMovingLeft(long timePassed)
{
if(pacMan.movingLeft == true)
{
pacMan.moveLeft(timePassed);
}
}
Rather than always moving the pacman by a constant distance (1 pixel, it appears) each time the timer runs, you should:
Set the timer to run as fast as possible (e.g. once every millisecond or less). Edit: if you set it too fast, the game may end up actually running slower, you'll have to experiment.
Calculate how much time has passed between each frame using the system clock and move the pacman by an amount proportional to that.
Doing the above will mean that if the system is "laggy," it will simply show fewer frames per second, rather than actually moving everything slower.
As I feared, you're basing the distance moved on the time chunk from the Timer. You shouldn't do this as all timers can be variable and unreliable, especially with small time chunks. Better to base movement on difference in system time. So yes, use a Timer or something to run your "game loop", but know the sprite's position and velocity using doubles, and calculate the distance to move based on velocity vector (math vector not Java Vector) * difference in system time. That way if the timer is delayed by say garbage collection, making the time chunk larger, the distance moved will be correspondingly greater and will look smoother.
You should look into creating a proper "main loop" or "game loop" as some call it. Take a look at the game structure part of this wikipedia article.. Basically those input events are happening\invoked from a separate thread than the main thread and they are directly modifying geometry of in game objects. Instead consider something like this for a main loop:
loop:
process collision detection
process animation (alters geometry of game objects)
process input (more on this later)
any other game specific logic
render screen
your process input could be something like this
if (globalInputObject.movingUp==true) {
hero.y -= 10;
}
if (globalInputObject.movingDown==true) {
hero.y += 10;
}
if (globalInputObject.movingLeft==true) {
hero.x -= 10;
}
if (globalInputObject.movingRight==true) {
hero.x += 10;
}
and your input handler would look something like this:
public void actionPerformed(ActionEvent evt) {
if (evt.button==UP_BUTTON) {
globalInputObject.movingUp=true;
}
if (evt.button==DOWN_BUTTON) {
globalInputObject.movingDown=true;
}
if (evt.button==LEFT_BUTTON) {
globalInputObject.movingLeft=true;
}
if (evt.button==RIGHT_BUTTON) {
globalInputObject.movingRight=true;
}
}
Basically the processing that you're doing in your "extra" threads (input thread) is minimal and therefore doesn't interfere with your main thread. Also, this method has the benefied of easily supporting multiple directions simultaneously (ie: UP+RIGHT = diagonal).
Only super high end games have more than a single thread (if they even need it at all). Dealing with synchronisation in a game is not good for performance.