I'm creating java game (I'm a beginner with this for now) and I'd like to start with some kind of platform game.
I'd like to know how I can make the player jump (I know how to move him up and down), but I don't know how how to make him go back down after going up.
Here is my code:
public void keyPress() {
if (listener.arrowUp) {
Jump();
}
}
private void Jump() {
if(player.get(1).getPosY() > maxJump) {
player.get(1).moveY(-10);
} else if(player.get(1).getPosY() == maxJump) {
player.get(1).moveY(85);
}
}
So.. the player moves -10px upwards as long as i press 'w' and when he hits maxJump (which is 375 and players position at the start is 465) he "teleports" back to 465 instead of sliding back down like he does when going up.. It's really hard to explain this without a video, but i hope somebody understands and can help me with this.
This question gives a basic answer to yours. Now in your jump function, you have to set the vertical_speed only once and only call fall() every frame and add some moveY.
Here are two alternatives:
Option 1. Simulating some very simple physics. You add forces to your player, so pressing the up arrow will add a force that makes the player move upwards. Gravity is constantly applied and thus it will gradually cancel out the force you applied when the up arrow was pressed. Perhaps you only want to use forces in the vertical direction you do something like this:
// Each frame
if(notOnTheGround){
verticalVelocity -= GRAVITATIONAL_CONSTANT;
}
// When user jumps
vertivalVelocity += JUMP_FORCE;
Option 2. An alternative is to kind of animate the jumps using projectile motion.
// Each frame
if(isJumping){
verticalVelocity = initialVelocity*sin(angle) - g*animationTime;
animationTime += TIME_STEP;
}
// When user jumps
isJumping = true;
animationTime = 0;
initialVelocity = ... // calculate initial velocity
Related
I'm creating a game like flappy bird where the bird flaps his wings only when the screen is touched, but I'm having a problem activating the animation when the screen is touched.
batch.draw(animation.getKeyFrame(myTimeState, false), x, y); //the myTimeState is 0 to render the 1st frame only.
Then when the screen is touched I do this:
//myTimeStep is just basically a controllable timeState for the animation only
if(Gdx.input.justTouched){
myTimeState = timeState;
}else if(Gdx.input.justTouched == false && animation.isAnimationFinished(timeState)){
myTimeState = 0;
}
I don't think the animation is able to play all the frames because myTimeStep become 0 immediately after finishing to touch the screen. Also I don't think this is the right way of doing it, if you guys have better ideas or solution please help. Thanks in advance.
There are probably several ways to achieve this. You'll need to increment your timeState, of course, and also it depends how long your animation is and if you want it to loop.
If you've created your animation to play only once, and then stop (until the screen is touched again), you could simply set your myTimeState to 0 when the screen is touched, and then increment it every frame. The animation will run through and then "stop" on its own when it reaches the end (as you said no loop). The next time someone touches the screen, your myTimeState is set back to 0 and the animation starts again.
Firstly, you have to ensure your animation's playmode is set to Animation.PlayMode.NORMAL. It's a default setting, but if you set it somewhere to LOOPED, nothing would work as expected.
Secondly, I wouldn't use Input.justTouched() in this case. Instead, a listener in your input processor would be a great fit. Here's an example with Stage. If you have no idea what input processor is, here's tutorial on event handling and class documentation.
stage.addListener(new ClickListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if(button == Input.Buttons.LEFT) {
timeState = 0;
}
return super.touchDown(event, x, y, pointer, button);
}
});
You can pick what's going to be displayed (animation's keyframe or sprite) based on result of animation.isAnimationFinished()
if(animation.isAnimationFinished(timeState)) {
//draw some sprite
} else {
//draw animation keyframe
}
I haven't checked it but there's a possibility, that this could lead to the last frame being cut out, because as soon as it gets displayed, animation.isAnimationFinished() will return true. I may be wrong, so you'll have to check it. If it becomes an issue, you can add your sprite as the last frame of your animation. When animation ends, it frezzes on the last frame, which would be your static sprite.
In both cases you'll get your animation played at the beginning of game because timeStep equal to 0. I see 2 solutions, I advise you to take the second:
Set timeStep to a large number, that is for sure larger than your animation's duration. Animation.isAnimationFinished() will then return true.
Introduce boolean variable isAnimationPlayed that:
is initialized with false,
gets set to true in your click listener,
gets set to false during isAnimationFinished(), which is called each frame only when isAnimationPlayed is true,
is used in draw() method to determine what to display.
You could just set your timeState to the duration of the animation.
I am trying to get the collision in my game to be exactly perfect. What I am testing is if you hit a wall with the player, you come to a stop. I only implemented the collision code for when the player hits the left side of a wall(when the wall is on the right side of the player). Here is the code.
if(entityOnRight){
if(player.getPositionCorner(SquareMapTuples.BOTTOM_RIGHT).x -
ent.getPositionCorner(SquareMapTuples.BOTTOM_LEFT).x > -.9f)
player.setMovementBooleans(false, false, false, false);
else
player.setMovementBooleans(true, false, false, false);
}
Note: If I go very slow, it will stop the player where I desire it to be stopped, but going fast, it won't do the collision the way I want
Essentially, the code states if the wall is on the right side, it will check the bottom right corner of the rectangle of the player, subtract the bottom left corner of the wall, and check if the distance between the two is 0.001. 0.001 is almost an unnoticeable distance, hence why I used that value. Here is the code for player.setMovementBooleans
public void setMovementBooleans(boolean canMoveRight, boolean canMoveLeft, boolean canMoveUp, boolean canMoveDown){
this.canMoveRight = canMoveRight;
if(canMoveRight == false && moveRight)
vel.x = 0;
}
The canMoveRight boolean in the Player class (not in parameters) is what allows you to be able to move, moveRight is when you are trying to move right. Here is some code that will better explain how these booleans interact:
//If you clicked right arrow key and you're not going
//Faster then the max speed
if(moveRight && !(vel.x >= 3)){
vel.x += movementSpeed;
}else if(vel.x >= 0 && !moveRight){
vel.x -= movementSpeed * 1.5f;
System.out.println("stopping");
//Make sure it goes to rest
if(vel.x - movementSpeed * 1.5f < 0)
vel.x = 0;
}
and:
if(Gdx.input.isKeyPressed(Keys.D) && canMoveRight)
moveRight = true;
else
moveRight = false;
So to give a summary, if you click the "D" key, it allows you to start moving. However if the boolean canMoveRight is false, it won't move you. Here is an image showing what happens (The player is yellow, the wall is green)
As you can see, the player goes much further then I want it to. It should stop at this point:
Any help with figuring out how to accomplish this is extremely appreciated!
Maybe the way you tried it is a bit too complicated :-). I suggest a simpler way from scratch: make the map and the player a com.badlogic.gdx.math.Rectangle instance. Now, in the following part of the code you make a check, whether after the move the player would still be inside the map, if yes then allow the move, if not, then don't allow:
if(Gdx.input.isKeyPressed(Keys.D){
float requestedX, requestedY;
//calculate the requested coordinates
Rectangle newPlayerPositionRectangle = new Rectangle(requestedX, requestedY, player.getWidth(), player.getHeight());
if (newPlayerPositionRectangle.overlaps(map) {
//move the player
} else {
//move the player only to the edge of the map and stop there
}
}
The best way to handle those collisions would be to use a physics engine like Box2D which already comes packed with Libgdx. When a collision occurs in Box2D a event gets fired and you can easly handle that event. So you should probably take a look here.
Another alternative to achieve this without physics would be to use logical rectanlges representing the player and walls (can also be polyline) and use Intersector class of libgdx.
which is here.
On the Dell Inspiron 15 3000, the touchpad doesn't have any physical left/right buttons. Instead, it is one giant touchpad that is pressure sensitive. I'm assuming it detects right/left clicks based off of hand position on the trackpad.
In my LWJGL application, I detect mouse button clicks with Mouse.isButtonDown(0). This works fine on computers with a mouse with physical buttons, but doesn't work on touchpads that lack physical buttons. Mouse.getButtonCount() returns 0.
Has anybody had any success in detecting if a mouse button is pressed, should the user be using a trackpad that doesn't have physical buttons?
I think, instead of using
org.lwjgl.input.Mouse
This class could be what you are searching for:
org.lwjgl.input.Controllers
http://legacy.lwjgl.org/javadoc/org/lwjgl/input/Controllers.html
Im not entirely sure though since I only have a mouse and no way to test this with a touchpad.
For those who find this in the future, I did find a fix:
You cannot, should there be no physical buttons, use the Mouse.isButtonDown() method. Instead, you are going to have to read the event buffer. To do so, I wrote my own helper class:
public class Mouse{
private static boolean button_left = false, button_right = false;
public static boolean isButtonDown(int button){
if(button == 0) return button_left;
if(button == 1) return button_right;
return false;
}
public static void update(){
while(org.lwjgl.input.Mouse.next()){
if(org.lwjgl.input.Mouse.getEventButton() == 0) button_left = org.lwjgl.input.Mouse.getEventButtonState();
if(org.lwjgl.input.Mouse.getEventButton() == 1) button_right = org.lwjgl.input.Mouse.getEventButtonState();
}
}
}
The update() method is called every tick, and as such I can get button states using Mouse.isButtonDown(button).
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 pretty new at java and I've been trying to write a method that draws a gradient from one configurable color to another. However, it appears that if statements inside of the for loop are being ignored.
How can I fix this? or is there something else I'm missing?
and usage of the method is:
Gradient.dVertical(Graphics,Top left corner X,Top left corner Y,Size X,Size Y,tarting Red Value,Starting Green Value,Starting Blue Value,Ending Red Value,Ending Green Value,Ending Blue Value);
EDIT: I figured out what the real problem was and I fixed it. When it should have been incremental down it was going up. So I added a couple more if statements and that cleared it up. Using random integers when calling the method did reveal another problem though. With certain values it will not finish drawing and it will just cut off in the middle. FIXED
Here's the fixed part of the code if anyone is interested
if (rrepeat == true)
{
//prevents division by zero
if(rrate!=0)
{
//for a rate that must repeat checks
//whether or not it is time to increment
check = k%rrate;
if (check==0)
{
if(ered<sred)
{
rr--;
}
if(sred<ered)
{
rr++;
}
}
else
{
rr = rr;
}
}
}
You need to be overriding the paint method.
Here's an example: Introduction to applets