I've been following along with ThinMatrix's OpenGL tutorial on making a game in Java recently. However as he uses LWJGL2, and I'm using LWJGL3, there's a few differences that require some work arounds. I'm stuck at one point in particular pertaining to creating a 3rd person character on a "player".
I've done enough so that when I click and drag the screen, the camera rotates around the player like it should. However when I let go and move my mouse to make another rotation, instead of continuing from where the position is, it resets it relative to where my second click is.
As LWJGL3 doesn't have a mouse.getDY() or mouse.getDX(), I made one in my DisplayManager class like so:
public float getDY() {
newMouseY = (float) getMouseY();
float dy = newMouseY - oldMouseY;
oldMouseY = newMouseY;
return dy;
}
public float getDX() {
newMouseX = (float) getMouseX();
float dx = newMouseX - oldMouseX;
oldMouseX = newMouseX;
return dx;
}
And I call it in my camera class like so:
private void calculatePitch(DisplayManager window) {
if (window.isMouseDown(GLFW.GLFW_MOUSE_BUTTON_LEFT)) {
float pitchChange = window.getDY() * 0.2f;
pitch -= pitchChange;
}
}
private void calculateAngleAroundPlayer(DisplayManager window) {
if (window.isMouseDown(GLFW.GLFW_MOUSE_BUTTON_LEFT)) {
float angleChange = window.getDX() * 0.3f;
angleAroundPlayer -= angleChange;
}
}
I'm just not sure if this should work and I'm missing something really obvious, or it can't be done this way. I'm pretty new to game dev.
Managed to figure out the issue, all I had to do was call my getDX() and getDY() functions again after the mouse has been pressed in my calculations:
private void calculatePitch(DisplayManager window) {
if (window.isMouseDown(GLFW.GLFW_MOUSE_BUTTON_LEFT)) {
float pitchChange = window.getDY(window) * 0.2f;
pitch += pitchChange;
}
window.getDY(window);
}
private void calculateAngleAroundPlayer(DisplayManager window) {
if (window.isMouseDown(GLFW.GLFW_MOUSE_BUTTON_LEFT)) {
float angleChange = window.getDX(window) * 0.3f;
angleAroundPlayer -= angleChange;
}
window.getDX(window);
}
Related
I am wondering what is a good approach on "unlimited mouse movement"? (Like in first person games where you can look around infinitely)
I am using OpenGL and LWJGL (which provides bindings for Java). I have the following possible bindings: https://www.lwjgl.org/customize (listed under contents)
Currently I am only using GLFW to handle the mouse input.
My current approach is the following, but obviously the cursor eventually reaches the screen edge:
public class MouseInput {
private final Vector2d previousPosition;
private final Vector2d currentPosition;
private final Vector2f displayVector;
private boolean inWindow = false;
// [some code here]
public void init() {
glfwSetCursorPosCallback(window.getHandle(), (windowHandle, xpos, ypos) -> {
currentPosition.x = xpos;
currentPosition.y = ypos;
});
glfwSetCursorEnterCallback(window.getHandle(), (windowHandle, entered) -> {
inWindow = entered;
});
// [some code here]
}
public void input() {
displayVector.x = 0;
displayVector.y = 0;
if (previousPosition.x > 0 && previousPosition.y > 0 && inWindow) {
double deltaX = currentPosition.x - previousPosition.x;
double deltaY = currentPosition.y - previousPosition.y;
if (deltaX != 0) {
displayVector.y = (float) deltaX;
}
if (deltaY != 0) {
displayVector.x = (float) deltaY;
}
}
previousPosition.x = currentPosition.x;
previousPosition.y = currentPosition.y;
}
// [some code here]
}
Now I can use the calculated displayVector somewhere else to rotate the camera.
Do I have to use something different than GLFW? I tried setting the position of the cursor back to the center after every input(), but that was very glitchy.
I am not looking for a correction of my code, but for a good approach which is the best practice.
glfwSetInputMode():
GLFW_CURSOR_DISABLED hides and grabs the cursor, providing virtual and unlimited cursor movement. This is useful for implementing for example 3D camera controls.
I am creating a Bouncing Ball Animation with JavaFX similar to the bouncing windows logo screen saver. The code I have now is decent but it will only bounce the ball in a clockwise manner. This is good generally but eventually the ball works itself around to a counter-clockwise rotation in which case it no longer looks realistic. I am stuck trying to find a way to calculate how the ball should bounce; in my mind it really comes down to what angel the ball comes in at. I am Using an AnimationTimer which Translates the ball a set amount each frame. When the Bounds of the ball meet a boundary the translating direction is changed it is at this meeting that I need a suggestion...
BallAnimation is an inner class.
class BallAnimation extends AnimationTimer{
private final Sphere ball;
private double movex = 0;
private double movey = 0;
private double xvariation = 0;
private double yvariation = 0;
private boolean right = true;
private boolean up = false;
private boolean changeColorRandomly = true;
private double rate = 1;
public BallAnimation(Sphere ball){
this.ball = ball;
ball.setLayoutX(200);
ball.setLayoutY(50);
}
public void handle(long now){
move(right,up);
Bounds ballBounds = ball.localToScene(ball.getBoundsInLocal());
if(ballBounds.intersects(rightWall.getBoundsInParent())){
calculateMotion(rightWall);
randomBounceAngle();
setRandomColor();
}
if(ballBounds.intersects(leftWall.getBoundsInParent())){
calculateMotion(leftWall);
randomBounceAngle();
setRandomColor();
}
if(ballBounds.intersects(ceiling.getBoundsInParent())){
calculateMotion(ceiling);
randomBounceAngle();
setRandomColor();
}
if(ballBounds.intersects(floor.getBoundsInParent())){
calculateMotion(floor);
randomBounceAngle();
setRandomColor();
}
}
private void calculateMotion(Line touchedWall){
if(touchedWall.equals(rightWall)){
right = false;
up = false;
}
if(touchedWall.equals(leftWall)){
right = true;
up = true;
}
if(touchedWall.equals(ceiling)){
right = true;
up = false;
}
if(touchedWall.equals(floor)){
right = false;
up = true;
}
}
public void move(boolean right, boolean up){
if(right && !up){
ball.setTranslateX((movex += (getRate() + xvariation)));
ball.setTranslateY((movey += (getRate() + yvariation)));
}
if(right && up){
ball.setTranslateX((movex += (getRate() + xvariation)));
ball.setTranslateY((movey -= (getRate() + yvariation)));
}
if(!right && up){
ball.setTranslateX((movex -= (getRate() + xvariation)));
ball.setTranslateY((movey -= (getRate() + yvariation)));
}
if(!right && !up){
ball.setTranslateX((movex -= (getRate() + xvariation)));
ball.setTranslateY((movey += (getRate() + yvariation)));
}
System.out.println("("+movex+", "+movey+")");
}
public double getRate(){
return rate;
}
public void setRate(double rate){
this.rate = rate;
}
public void randomBounceAngle(){
double ran = Math.random();
if(ran >= .50){
//shallow bounce angle
xvariation = 3;
yvariation = 2;
}else{
//sharp bounce angle
xvariation = 2;
yvariation = 3;
}
}
... The problem is when the ball hits the right boundary it bounces down and away, the bottom it bounces up and left, left boundary: up and right, ceiling: right and down. This is fine most of the time but sometimes it needs to bounce the other way.
Well, in a world of perfect physics, in angle is equal to out angle. If you are using an x/y axis, For reflection off the x-axis, negate the y component of the ball's velocity. For reflection off the y-axis, negate the x component of the ball's velocity.
I re-wrote pong in javascript using layers and detecting keyboard strokes for paddle control (this was in '00 or '01 with Netscape 4.7x). I cheated, and set up functions to move the ball in 8 directions. If the ball was traveling along an axis (straight left/right or up/down) a quick random number provided a different bounce coming out. Otherwise, bounce out at same angle in.
Here is a function to reflect a vector around a normal. It can be used to create a bounce, by reflecting the velocity vector of the ball around the normal of the wall (or the normal of the side of another object) that the ball is bouncing off of.
private Point2D reflect(Point2D vector, Point2D normal) {
return vector.subtract(normal.multiply(vector.dotProduct(normal) * 2));
}
It is part of an implementation for a sample breakout game I created based on the example code in this question.
The code shown for the vector-based reflection uses the formula provided in the answer to this question, which is translated directly to JavaFX classes:
How to get a reflection vector?
𝑟=𝑑−2(𝑑⋅𝑛)𝑛 where 𝑑⋅𝑛 is the dot product and 𝑛 must be normalized.
Please note that, if you search, there are many math tutorials and Stackoverflow questions that talk about functions and methods for performing reflection.
A particular case for balls bouncing off vertical or horizontal surfaces such as walls or bricks in a breakout game is that the lines which the ball is bouncing off of are parallel to the x and y axes of the coordinate system, so the bounce can be performed by negating the x or y values of the velocity vector. See the example code in this question or answers to other questions on reflection for an example of this simplification if it is something you wish to use.
if (topWall) {
dy = dy * -1;
}
if (leftWall || rightWall) {
dx = dx * -1;
}
if(bottomWall) {
dy = dy * -1;
}
I have a video game in which an arrow moves towards the side where it is pointing, after rotation the arrow, example:
I need to move the sprite To the same direction in which the arrow points after it has been rotation.
A bit of code As I'm trying to do:
int count = 0;
#Override
protected void handleInput() {
if(Gdx.input.justTouched()){
// move to the direction of pointing:
arrow.setPosition(x, y);
}
}
public void update(float dt){
count++;
// rotate sprite:
arrow.setRotation(count);
}
In the book "Beginning Java Game Development with LibGDX" the author makes a game that I think demonstrates the behaviour you want. The game is "Starfish Collector" from chapter 3. The player moves a turtle to collect starfish. The left and right arrow keys rotate the turtle, and the up arrow key moves the turtle forward in the direction he is currently facing.
The source code for the game can be downloaded from the author's Github account here. (I don't know why he put it in a zip file.)
The relevant code looks like this:
#Override
public void update(float dt) {
// process input
turtle.setAccelerationXY(0, 0);
if (Gdx.input.isKeyPressed(Keys.LEFT)) {
turtle.rotateBy(90 * dt);
}
if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
turtle.rotateBy(-90 * dt);
}
if (Gdx.input.isKeyPressed(Keys.UP)) {
turtle.accelerateForward(100);
}
// ...
Where turtle extends some custom classes that extend Actor.
The code for accelerateForward looks like this:
public void accelerateForward(float speed) {
setAccelerationAS(getRotation(), speed);
}
And then the code for setAccelerationAS looks like this:
// set acceleration from angle and speed
public void setAccelerationAS(float angleDeg, float speed) {
acceleration.x = speed * MathUtils.cosDeg(angleDeg);
acceleration.y = speed * MathUtils.sinDeg(angleDeg);
}
Note that this last bit of code is probably exactly what user unexistential was referring to.
(I recommend this book if you're learning LibGDX and game development. It's very good.)
See also:
Beginning Java Game Development with LibGDX by Lee Stemkoski
Book's source code
The simplest way would be to use the sine and cosine of the rotation amount to determine the x and y components of the translation vector.
I resolved with this page: enter link description here
float mX = 0;
float mY = 0;
int velocity = 5;
private float posAuxX = 0;
private float posAuxY = 0;
int count = 0;
public void update(float dt){
count2++;
flecha.setRotation(count2);
if (count2 >= 360){
count2 = 0;
}
position = new Vector2((float) Math.sin(count2) * velocity,
(float) Math.cos(count2 * velocity));
mX = (float) Math.cos(Math.toRadians(flecha.getRotation()));
mY = (float) Math.sin(Math.toRadians(flecha.getRotation()));
position.x = mX;
position.y = mY;
if (position.len() > 0){
position = position.nor();
}
position.x = position.x * velocity;
position.y = position.y * velocity;
posAuxX = flecha.getX();
posAuxY = flecha.getY();
}
flecha.setPosition(posAuxX, posAuxY);
I've overridden the LibGdx Pan gesture method for a different functionality (a selector). However, I want the pan functionality to use two fingers(pointers) instead. Is this possible?
It's the same question as this post, however his is specific to iPhone and not LibGdx:
How to implement the traditional imageView-inside-a-scrollView pan gesture with two fingers instead of one?
the pan() method will only fire with one finger, not two. I was thinking of keeping track of number of fingers used, by setting a variable in touchDown() using the int pointer variable, however the pan() method will not fire when there are 2 fingers in use.
Any suggestions? Cheers
After 3+ years of research I finally made it.
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
// Calculate distances
float initialDistance = initialPointer1.dst(initialPointer2);
float distance = pointer1.dst(pointer2);
// Calculate pinch coordinates
float initialPinchX = (initialPointer1.x + initialPointer2.x) / 2;
float initialPinchY = (initialPointer1.y + initialPointer2.y) / 2;
float pinchX = (pointer1.x + pointer2.x) / 2;
float pinchY = (pointer1.y + pointer2.y) / 2;
// This to avoid first time zooming or panning horrible behavior
if (lastZoomDistance == 0) {
lastZoomDistance = initialDistance;
}
if (lastPinchX == lastPinchY && lastPinchX == 0) {
lastPinchX = initialPinchX;
lastPinchY = initialPinchY;
}
// Zoom
float distanceDifference = distance - lastZoomDistance;
camera.zoom -= distanceDifference / 300;
// Pan
float deltaX = (pinchX - lastPinchX) * camera.zoom;
float deltaY = (pinchY - lastPinchY) * camera.zoom;
camera.translate(-deltaX, deltaY);
// We need to update these for future calculations
lastZoomDistance = distance;
lastPinchX = (pointer1.x + pointer2.x) / 2;
lastPinchY = (pointer1.y + pointer2.y) / 2;
return false;
}
I managed to jig the pinch() method around to calculate a combined two finger panning and zooming gesture, instead of using zoom().
Here's some code which achieves this using the pinch method, by looking at how far the first finger has been dragged from its initial position. The second finger is ignored.
Gdx.input.setInputProcessor(new GestureDetector(new GestureDetector.GestureAdapter() {
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
float panAmount = pointer1.x - initialPointer1.x;
// ...
return true;
}
})));
To add onto Luis' answe, sometimes you may want Pan/ Zoom to act as exclusive actions (only one can happen at a time). If that's what you're after, this may be useful
val targetVector1 = Vector2(pointer1).sub(initialPointer1)
val targetVector2 = Vector2(pointer2).sub(initialPointer2)
val isZoom = targetVector1.hasOppositeDirection(targetVector2)
val isPan = !isZoom
I have a very simple animation task for Java. I need to create a basic "Wheel of Fortune Applet". Basically what will be displayed is a wheel and a button. When that button is pressed I want it to select a random # of degrees (say in the range of 720-3600) and spin the wheel that many degrees. I will then use some logic to convert that degree number to a money value. My problem is in the animation, how do I get an image to spin at a constant pace for x number of degrees? Is there a swing function for that? Help would be much appreciated, I don't need to know anything else about Java animation right now besides that.
I'm going to assume that you understand how to rotate an image once. If you don't, you can probably find that with a quick google search.
What you need is a background process that rotates it for you. It works like this:
/**
* Warning - this class is UNSYNCHRONIZED!
*/
public class RotatableImage {
Image image;
float currentDegrees;
public RotateableImage(Image image) {
this.image = image;
this.currentDegrees = 0.0f;
this.remainingDegrees = 0.0f;
}
public void paintOn(Graphics g) {
//put your code to rotate the image once in here, using current degrees as your rotation
}
public void spin(float additionalDegrees) {
setSpin(currentDegrees + additionalDegrees);
}
public void setSpin(float newDegrees) {
currentDegrees += additionalDegrees;
while(currentDegrees < 0f) currentDegrees += 360f;
while(currentDegrees >= 360f) currentDegrees -= 360f;
}
}
public class ImageSpinner implements Runnable {
RotateableImage image;
final float totalDegrees;
float degrees;
float speed; // in degrees per second
public ImageSpinner(RotatableImage image, float degrees, float speed) {
this.image = image;
this.degrees = degrees;
this.totalDegrees = degrees;
this.speed = speed;
}
public void run() {
// assume about 40 frames per second, and that the it doesn't matter if it isn't exact
int fps = 40;
while(Math.abs(degrees) > Math.abs(speed / fps)) { // how close is the degrees to 0?
float degreesToRotate = speed / fps;
image.spin(degreesToRotate);
degrees -= degreesToRotate;
/* sleep will always wait at least 1000 / fps before recalcing
but you have no guarantee that it won't take forever! If you absolutely
require better timing, this isn't the solution for you */
try { Thread.sleep(1000 / fps); } catch(InterruptedException e) { /* swallow */ }
}
image.setSpin(totalDegrees); // this might need to be 360 - totalDegrees, not sure
}
}