Get delta Mouse wheel on LWJGL3 (GLFW) - java

I'm trying to make a 3D camera around a player on a game made with LWJGL3.
With the mouse scroll wheel you'll be able to zoom on the player.
How my function should be ?
How I query every event the mousewheel value.
glfwSetScrollCallback(window.getWindowHandle(), (windowHandle, xoffset, yoffset) -> {
currentMouseWheel.x = xoffset;
currentMouseWheel.y = yoffset;
});
My function to get Scroll delta based on the previous call :
(PS : input is called each gameLoop)
public void input(Window window) {
dMouseWheel.x = 0;
dMouseWheel.y = 0;
if (inWindow) {
double dx = currentMouseWheel.x - previousMouseWheel.x;
double dy = currentMouseWheel.y - previousMouseWheel.y;
if (dx != 0) {
dMouseWheel.x = (float) dx;
}
if (dy != 0) {
dMouseWheel.y = (float) dy;
}
}
previousMouseWheel.x = currentMouseWheel.x;
previousMouseWheel.y = currentMouseWheel.y;
}
xoffset and yoffset are never equals to 0.
I have to make big impulse on the scrollwheel to see the delta change.
What should I do ?
Can you give me an example ?
UPDATE : I found out !
How to do it :
First of all set 2 vectors variables :
private Vector2d currentMouseWheel;
private Vector2f dMouseWheel;
Then in your Scroll callback :
glfwSetScrollCallback(window.getWindowHandle(), (windowHandle, xoffset, yoffset) -> {
currentMouseWheel.x = xoffset;
currentMouseWheel.y = yoffset;
});
Then each game loop iteration, you call a function to update it
public void input() {
dMouseWheel.x = 0;
dMouseWheel.y = 0;
if (inWindow) {
dMouseWheel.x = (float) currentMouseWheel.x;
dMouseWheel.y = (float) currentMouseWheel.y;
}
currentMouseWheel.x = 0;
currentMouseWheel.y = 0;
}
Then you'll have dMouseWheel with the correct Scroll delta !

Related

openGL in java: moving camera with TouchEvent

I need to create a movement/changing position of the camera with the x,y axes by touching screen. I've read many of the previous questions, but nowhere noticed something that will solve my problem.
how can i use this code ? :
class ESSurfaceView extends GLSurfaceView {
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float mPreviousX;
private float mPreviousY;
#Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
if (y > getHeight() / 2) {
dx = dx * -1 ;
}
if (x < getWidth() / 2) {
dy = dy * -1 ;
}
GLRenderer.setAngle(
GLRenderer.getAngle() +
((dx + dy) * TOUCH_SCALE_FACTOR));
requestRender();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
public ESSurfaceView(Context context)
{
super(context);
setEGLContextClientVersion(2);
GLRenderer renderer = new GLRenderer();
setRenderer(renderer);
// Render the view only when there is a change in the drawing data
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}}
Offical Android Training has an example (mostly identically to yours) for that:
https://developer.android.com/training/graphics/opengl/touch.html
It also offers complete source.
By the way - you never move the camera in openGL - you move the world.
For further understanding please read:
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
This should give you a better understanding on how things work...

Trying to do a simple Jump

I'm trying to learn how to make a 2D Game without Game Engines, anyways I already created a background scrolling right now my goal is to make my character jump. But the thing is whenever I start my app the character is spinning up and down and it will just go away to the background.
Here's my character code
public class Deer extends GameCharacter {
private Bitmap spritesheet;
private double dya;
private boolean playing;
private long startTime;
private boolean Jump;
private Animate Animation = new Animate();
public Deer(Bitmap res, int w, int h, int numFrames) {
x = 20;
y = 400;
dy = 0;
height = h;
width = w;
Bitmap[] image = new Bitmap[numFrames];
spritesheet = res;
for (int i = 0; i < image.length; i++)
{
image[i] = Bitmap.createBitmap(spritesheet, i*width, 0, width, height);
}
Animation.setFrames(image);
Animation.setDelay(10);
startTime = System.nanoTime();
}
public void setJump(boolean b){
Jump = b;
}
public void update()
{
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100)
{
}
Animation.update();
if(Jump){
dy = (int)(dya+=5.5);
}
else{
dy = (int)(dya+=5.5);
}
if(dy>14)dy = 14;
if(dy>14)dy = -14;
y += dy*2;
dy = 0;
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(Animation.getImage(),x,y,null);
}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
public void resetDYA(){dya = 0;}
}
x - character's horizontal position
y - character's vertical position
dx - character's horizontal acceleration
dy - character's vertical acceleration
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN) {
if(!deer.getPlaying()) {
deer.setPlaying(true);
}
deer.setJump(true);
return true;
}
return super.onTouchEvent(event);
}
I can't say for sure if this is the only problem because you have other suspicious code but it looks like you jump no matter what.
if(Jump){
dy = (int)(dya+=5.5);
} else {
dy = (int)(dya+=5.5);
}
If Jump is true you set the vertical acceleration. But you also set the vertical acceleration to the same value if Jump is false. You also don't show in your code where Jump is ever set to false.
Another odd bit of code is:
if(dy>14)dy = 14;
if(dy>14)dy = -14;
Here, if dy>14 you set it to 14. Then you check dy>14 immediately after. Of course, this time it's false. But because those two conditions are the same the second one will never pass since the one before it ensures it won't. The only other option is they both fail. IOW, you'll never be able to enter the second if.
All that aside, I'm not sure why you're taking this approach. You can simply rely on physics equations with constant acceleration, give an initial velocity, check for a collision with the ground (or at least the original height), and just let it run. For example:
// These are the variables you need.
int x = 200, y0 = 0, y = 0, velocity = 15;
double t = 0.0, gravity = -9.8;
// This is the statement that should run when you update the GUI.
// It is the fundamental equation for motion with constant acceleration.
// The acceleration is the gravitational constant.
y = (int) (y0 + velocity * t + .5 * gravity * t * t);
if (y < 0) {
y = y0 = 0;
//Stop jumping!
Jump = false;
} else {
// Swap the y values.
y0 = y;
// Increase the time with the frame rate.
t += frameRate;
}
// Draw the character using the y value
The best part about this is you don't need to worry about when you get to the maximum height because the equation will automatically bring you down. It also looks more natural as if the mechanics are real. Try it out.
A simple Swing example that you can play around with. Note that the values are different to deal with the way the components are drawn to the screen. Normally, you would deal with that with transformations but this will do for the task.
public class Main {
static Timer timer;
Main() {
JFrame frame = new JFrame("Hello sample");
frame.setSize(new Dimension(550, 550));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new MyPanel();
frame.add(panel);
frame.setVisible(true);
timer = new Timer(5, (e) -> panel.repaint());
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(Main::new);
}
class MyPanel extends JPanel {
int x = 200, y0 = 300, y = 0, w = 200, h = 200, v = -8;
double t = 0.0, gravity = 9.8;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
y = (int) (y0 + v * t + .5 * gravity * t * t);
if (y > 300) {
y = y0 = 300;
// To prevent it from stopping comment the timer.stop() and
// uncomment the t = 0.0 statements.
//t = 0.0;
timer.stop();
} else {
y0 = y;
t += .025;
}
g.drawOval(x, y, w, h);
}
}
}

Input events not working simultaneously on android devices in libgdx

I am making a simple platform game in Libgdx... in which I have made the player to move left, move right and jump. The code works fine on Desktop but on Android devices, Jump is not fired when the player moves left or right. It looks strange. Here is my code...
private void updatePlayerForUserInput(float deltaTime)
{
// check input and apply to velocity & state
if ((Gdx.input.isKeyPressed(Keys.SPACE) || isTouched(0.87f, 1,0,1f)) && world.player.grounded)
{
world.player.velocity.y += world.player.JUMP_VELOCITY;
world.player.state =2;
world.player.grounded = false;
}
if (Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A) || isTouched(0, 0.1f,0,1f))
{
world.player.velocity.x -=world.player.MAX_VELOCITY;
if (world.player.grounded)
world.player.state =1;
world.player.facesRight = false;
}
if (Gdx.input.isKeyPressed(Keys.RIGHT) || Gdx.input.isKeyPressed(Keys.D) || isTouched(0.2f, 0.3f,0,1f))
{
world.player.velocity.x =world.player.MAX_VELOCITY;
if (world.player.grounded)
world.player.state =1;
world.player.facesRight = true;
}
}
private boolean isTouched(float startX, float endX , float startY, float endY)
{
// check if any finge is touch the area between startX and endX
// startX/endX are given between 0 (left edge of the screen) and 1 (right edge of the screen)
for (int i = 0; i < 2; i++)
{
float x = Gdx.input.getX() / (float) Gdx.graphics.getWidth();
float y = Gdx.input.getY() / (float) Gdx.graphics.getHeight();
if (Gdx.input.isTouched(i) && (x >= startX && x <= endX) && (y>=startY && y<= endY))
{
return true;
}
}
return false;
}
I took the idea from the demo platform game SuperKoalio by mzencher at
https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/superkoalio/SuperKoalio.java
Please suggest
This code:
float x = Gdx.input.getX() / (float) Gdx.graphics.getWidth();
float y = Gdx.input.getY() / (float) Gdx.graphics.getHeight();
Is always getting the x/y from the first active touch. You need to check the "i'th" active touch. Like this:
for (int i = 0; i < 20; i++) {
if (Gdx.input.isTouched(i)) {
float x = Gdx.input.getX(i) / (float) Gdx.graphics.getWidth();
float y = Gdx.input.getY(i) / (float) Gdx.graphics.getHeight();
if ((x >= startX && x <= endX) && (y>=startY && y<= endY)) {
return true;
}
}
return false;
Also, you should probably iterate through all 20 possible touch points, since up to 20 touch points can be tracked by the hardware. (Try putting three fingers in the "jump" region and then add a fourth finger in the "move left" region.)

How to smoothly zoom a canvas?

How could I smoothly create a zoom animation for a canvas?
GWT provides a onMouseWheel(MouseWheelEvent evt) method and a evt.getDeltaY() to get the amount of scroll wheel.
Problem here is, that every wheel movement executes this method, and if I call a canvas redraw in the method itself, things get very laggy.
So I thought of somehow making an animation for the zooming. But how?
I thought about creating a Timer, but have no real idea, as there is only the mousewheelevent as starting point, but no end point that the user finished zooming with the wheel...
Here is my scalable image class that I use to zoom into images, it is very quick and responsive. I found an example somewhere and made some minor modifications to make it more responsive. I don't remember the original source or I would give them credit here.
public class ScalableImage extends Composite implements MouseWheelHandler, MouseDownHandler, MouseMoveHandler, MouseUpHandler {
Canvas canvas = Canvas.createIfSupported();
Context2d context = canvas.getContext2d();
Canvas backCanvas = Canvas.createIfSupported();
Context2d backContext = backCanvas.getContext2d();
int width;
int height;
Image image;
ImageElement imageElement;
double zoom = 1;
double totalZoom = 1;
double offsetX = 0;
double offsetY = 0;
boolean mouseDown = false;
double mouseDownXPos = 0;
double mouseDownYPos = 0;
public ScalableImage(Image image) {
initWidget(canvas);
//width = Window.getClientWidth() - 50;
width = image.getWidth() + 200;
height = image.getHeight() + 200;
//canvas.setWidth(width + "px");
//canvas.setHeight(height + "px");
canvas.setCoordinateSpaceWidth(width);
canvas.setCoordinateSpaceHeight(height);
//backCanvas.setWidth(width + "px");
//backCanvas.setHeight(height + "px");
backCanvas.setCoordinateSpaceWidth(width);
backCanvas.setCoordinateSpaceHeight(height);
canvas.addMouseWheelHandler(this);
canvas.addMouseMoveHandler(this);
canvas.addMouseDownHandler(this);
canvas.addMouseUpHandler(this);
this.image = image;
this.imageElement = (ImageElement) image.getElement().cast();
mainDraw();
}
public void onMouseWheel(MouseWheelEvent event) {
int move = event.getDeltaY();
double xPos = (event.getRelativeX(canvas.getElement()));
double yPos = (event.getRelativeY(canvas.getElement()));
if (move < 0) {
zoom = 1.1;
} else {
zoom = 1 / 1.1;
}
double newX = (xPos - offsetX) / totalZoom;
double newY = (yPos - offsetY) / totalZoom;
double xPosition = (-newX * zoom) + newX;
double yPosition = (-newY * zoom) + newY;
backContext.clearRect(0, 0, width, height);
backContext.translate(xPosition, yPosition);
backContext.scale(zoom, zoom);
mainDraw();
offsetX += (xPosition * totalZoom);
offsetY += (yPosition * totalZoom);
totalZoom = totalZoom * zoom;
buffer(backContext, context);
}
public void onMouseDown(MouseDownEvent event) {
this.mouseDown = true;
mouseDownXPos = event.getRelativeX(image.getElement());
mouseDownYPos = event.getRelativeY(image.getElement());
}
public void onMouseMove(MouseMoveEvent event) {
if (mouseDown) {
backContext.setFillStyle("white");
backContext.fillRect(-5, -5, width + 5, height + 5);
backContext.setFillStyle("black");
double xPos = event.getRelativeX(image.getElement());
double yPos = event.getRelativeY(image.getElement());
backContext.translate((xPos - mouseDownXPos) / totalZoom, (yPos - mouseDownYPos) / totalZoom);
offsetX += (xPos - mouseDownXPos);
offsetY += (yPos - mouseDownYPos);
mainDraw();
mouseDownXPos = xPos;
mouseDownYPos = yPos;
}
}
public void onMouseUp(MouseUpEvent event) {
this.mouseDown = false;
}
public void mainDraw() {
backContext.drawImage(imageElement, 100, 100);
buffer(backContext, context);
}
public void buffer(Context2d back, Context2d front) {
front.beginPath();
front.clearRect(0, 0, width, height);
front.drawImage(back.getCanvas(), 0, 0);
}
}

How to apply gravity when an object fall?

I have an object(which is a ball) having its position at the top of the screen that fall directly whenever I start running the program. The problem is that the ball fall to its constant speed, I want it to fall accelerating with gravity effects and when it reach the ground, I want it to bounce a few more times before it stop moving. Could someone help me about this?
Here's what I've tried:
public class Balls
{
private double x;
private double y;
private double speed;
private double mass;
private final double gravity = -9.8;
private final double width = 100;
private double height = 100;
private final Board board;
private boolean isFalling = false;
private double distance_y;
private double distance_x = 0;
public Balls(double x, double y, double speed, double mass, Board board)
{
this.x = x;
this.y = y;
this.board = board;
this.speed = convertToMeterSpeed(speed);
this.mass = mass;
}
private double convertToMeterSpeed(double speed)
{
return speed / 3.6;
}
public void moveBall(long dt)
{
double time = dt / 1e9; // seconds
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (distance_y >= height)
{
distance_y = distance_y + (0.5 * gravity * (time * time)); // represents the 1/2,
distance_y = board.getHeight() - height;
y += velocity_y;
}
else
{
isFalling = false;
}
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
}
}
}
public void render(Graphics2D g2d)
{
g2d.fillOval((int) x, (int) y, (int) width, (int) height);
}
}
speed = v0 + gt^2/2,
where
v0 - initial speed
g = 9.81 on Earth.
t - time
Now you can calculate the speed at any time.
You probably want to define a maximum speed (terminal velocity) so your ball doesn't accelerate to an enormous speed. Gravity accelerates at 9.8m/s/s. Once the ball hits the "ground" you just reverse the speed and update the current position to make it bounce, then on your next iteration gravity will be applied again so it will go back down. Eventually, the speed will get to 0 as the ball doesnt bounce so much, and will stop.
Here's an (untested) example:
private static final double GRAVITY = 9.8;
private static final double TERMINAL_VELOCITY = 100;
private double speed;
private int current_y;
public void fallAndBounce() {
speed = speed + GRAVITY;
if (speed > TERMINAL_VELOCITY) { speed = TERMINAL_VELOCITY; }
if (current_y >= bottomOfScreen)
{
//We have hit the "ground", so bounce back up. Reverse
//the speed and divide by 4 to make it slower on bouncing.
//Just change 4 to 2 or something to make it faster.
speed = -speed/4;
}
current_y += speed;
}
Your problem is that you are trying to animate a ball falling, but you are instead writing an algorithm for solving its position given a certain time.
This means you should take your time variable dt completely out of the equation, and just move your ball with each iteration of a loop like this:
while (true)
{
moveBall();
render();
try {
Thread.sleep(10)
} catch(InterruptedException e) {
e.printStackTrace();
}
}
Also, change your variables slightly:
// Add this to your variables
private final double GRAVITY = -9.8; // Final variables should be capitalized
private final double TERMINAL_VELOCITY = -30; // Whatever you want it to be
Here is the main change:
public void moveBall()
{
double diameter_y = height / 2.0;
double radius = (diameter_y / 2.0);
double velocity_y = speed * dt / 1e9;
distance_y = board.getHeight() - y;
if (distance_y - radius > 0)
{
isFalling = true;
}
if (isFalling)
{
if (height < distance_y)
{
if (velocity_y <= TERMINAL_VELOCITY)
velocity_y += GRAVITY; // implementing acceleration (gravity)
// just means adding it to velocity.
y += velocity_y;
}
Really, I don't know how this was possibly working before.

Categories

Resources