My game only has 2 classes right now, "MyGdxGame" and "Player". I've added a method jump() to my Player class and overridden the touchDown() method to call jump every time the screen is tapped:
public void jump() {
startTime = TimeUtils.nanoTime();
elapsedTime = TimeUtils.timeSinceNanos(startTime);
boolean jumpTime = elapsedTime < 2000000001;
while (jumpTime) {
moveBy(xSpeed, ySpeed);
}
moveBy(xSpeed, -ySpeed);
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
//moveBy(xSpeed, ySpeed);
jump();
return true;
}
Right now when the screen is tapped the sprite goes up but doesn't come back down. before the screen is tapped the sprite is moving from left to right at constant speed xSpeed. Any ideas?
edit: I built my project then ran it again. It freezes when I tap the screen then crashes lol
The boolean jumpTime is never getting updated inside the while loop in the jump() method.
Try:
startTime = TimeUtils.nanoTime();
long jumpTime= 2000000001;
while (TimeUtils.timeSinceNanos(startTime) < jumpTime) {
moveBy(xSpeed, ySpeed);
}
moveBy(xSpeed, -ySpeed);
Related
I'm currently making a 2d infinite runner esque game that has a release date of Halloween. I've nearly finished the game itself and I've just added a main menu and am currently in the process of making a pause menu. I'm having a big issue with setting the screens though. Setting the screen from my main menu into the game works perfectly fine but when I set the screen back to the main menu a few weird things happen:
Nothing in the spriteBatch renders, everything is just a black box (MainMenuScreen)
If I choose to go back to the game I find that not everything is reset like when the screen is initially set to GameScreen
Here's a video of the issue
Here's the code for how I switch screens:
From when the game is first opened to main menu:
public class RadiationPigeon extends Game {
public static final float PPM = 100;
public static SpriteBatch batch;
#Override
public void create () {
batch = new SpriteBatch();
setScreen(new MainMenuScreen(this));
}
#Override
public void render () {
super.render();
}
#Override
public void dispose () {
batch.dispose();
}}
From MainMenuScreen to GameScreen:
private RadiationPigeon radiationPigeon;
public MainMenuScreen(RadiationPigeon radiationPigeon){
this.radiationPigeon = radiationPigeon;
}
playButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
radiationPigeon.setScreen(new GameScreen(radiationPigeon));
//I give GameScreen radiationpigeon so that the screen can be set back to MainMenu
}
});
From GameScreen to MainMenu:
private RadiationPigeon radiationPigeon;
public GameScreen(RadiationPigeon radiationPigeon){
world.setContactListener(new ContactListener());
Timer timer = new Timer();
timer.schedule(new BatAttackChanceCounter(), 0, 1000);
this.radiationPigeon = radiationPigeon;
}
pauseButton.addListener(new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return true;
}
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
//paused = true;
radiationPigeon.setScreen(new MainMenuScreen(radiationPigeon));
}
});
Just for reference, here's my render method of both screens:
MainMenuScreen:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
RadiationPigeon.batch.begin();
stage.draw();
RadiationPigeon.batch.end();
}
GameScreen:
#Override
public void render(float delta) {
update(delta);
Gdx.gl.glClearColor(0, 0,0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
RadiationPigeon.batch.setProjectionMatrix(pigeoncam.combined);
RadiationPigeon.batch.begin();
//RadiationPigeon.batch.draw(pausedScreen, pigeoncam.position.x - (250 / RadiationPigeon.PPM), pigeoncam.position.y - pigeoncam.viewportHeight / 2, 5, 5);
RadiationPigeon.batch.end();
b2dr.render(world, pigeoncam.combined);
stage.draw();
hud.stage.draw();
}
After lots of trial and error I finally resolved my issue. There was nothing wrong with how I set my screens (for anyone having trouble with setting screens the code I provided works). The problem was with the actual buttons and images. I had made some of them static because I needed to use the same buttonstyles and fonts in GameScreen. I thought that would save memory, however, once they were accessed outside the screen in which they were created (MainMenuScreen) they would lose all their values essentially making them empty without making them null.
A lack of understanding on how buttons worked is what caused the issue
EDIT:
Turns out a lack of understanding on how static variables work was the real issue. On android when you minimize an android app the java cycle doesn't stop and as such the items are "kept alive"
So I am currently busy with a kind of pong game for android. All i have currently is the paddle and the ball. The controls for the player (the paddle) is as followed:
If player touches on left side of screen, paddle goes left
If player touches on right side of screen, paddle goes right
Actually the above 2 points work fine, but what bothers me, is that when im holding right with my right finger, and after that release it and really fast holding left with my left finger, the paddle only executes one time "going left", and then stops, while I am still holding left. (and vice versa)
I discovered this only happens if I use two fingers. If im holding down right with my finger, and try to go really fast to press the other side, it doesnt stop and actually keeps going left.
But it is important to use two fingers, since that is the way how the game should be played.
This all may be explained unclear, so you can ask in the comments more specific questions.
Player.java: http://pastebin.com/pdFZJTRB
MyInputProcessor.java: http://pastebin.com/XPzi8JPB
I think your problem resides in the fact that you have the touchDown boolean being shared between the left and right sides. If you press the left side fast enough, the touchDown for the left finger gets set to true before the touchDown for the right finger is set to false, thus making them all false. Try something like this instead:
package com.nahrot.teleportball;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.math.Vector2;
public class MyInputProcessor implements InputProcessor
{
public Vector2 leftTouchPos = new Vector2();
public Vector2 rightTouchPos = new Vector2();
public boolean touchLeft = false;
public boolean touchRight = false;
#Override
public boolean keyDown(int keycode)
{
return false;
}
#Override
public boolean keyUp(int keycode)
{
return false;
}
#Override
public boolean keyTyped(char character)
{
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button)
{
if(sideTouched(screenX, true))
{
touchLeft = true;
leftTouchPos.set(screenX, screenY);
}
if(sideTouched(screenX, false))
{
touchRight = true;
rightTouchPos.set(screenX, screenY);
}
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button)
{
if(sideTouched(screenX, true))
{
touchLeft = false;
}
if(sideTouched(screenX, false))
{
touchRight = false;
}
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer)
{
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY)
{
return false;
}
#Override
public boolean scrolled(int amount)
{
return false;
}
private boolean sideTouched(int x, boolean checkLeft)
{
if(checkLeft)
{
if(x <= Gdx.graphics.getWidth() / 2)
return true;
}
else
{
if(x > Gdx.graphics.getWidth() /2)
return true;
}
return false;
}
}
Here, I separated the booleans and vectors into left side and right side, and made a convenience function for checking whether a touchDown or touchUp is on the right or left side of the screen, and adjusted the corresponding booleans and vectors accordingly. I assume the vector was needed to check which side was pressed anyway, so I suspect you could work it so that all you need is the two booleans for the sides touched. This code is untested, by the way, but you should get the idea if it doesn't work.
So I was told to create a simple game in android using canvas only for a school project (meaning I can't use any extensions or game engines beside the ones that come with android), and I wanted to create a simple 2d game with a player walking around.
I did it like that:
public GameView(Context c) {
// TODO Auto-generated constructor stub
super(c);
this.c=c;
this.Sprite=BitmapFactory.decodeResource(getResources(), R.drawable.walk1);
this.Sprite=Bitmap.createScaledBitmap(Sprite, Sprite.getWidth()*2, Sprite.getHeight()*2, false);
sprite2=new Sprite("Spicy",Sprite);
this.requestFocus();
this.setFocusableInTouchMode(true);
animate1();
}
I created a view class, loaded a simple player sprite, created sprite class and an handler -
public void animate1(){
handlerAnimation100 = new Handler();
final Runnable r = new Runnable() {
public void run() {
invalidate();
handlerAnimation100.postDelayed(this, 1);
}
};
handlerAnimation100.postDelayed(r, 1);
}
that does invalidate every 0.001 seconds for the game time and animation.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
sprite2.Draw(canvas);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
sprite2.Update(keyCode);
invalidate();
return false;
}
on onDraw i called the draw function in the sprite class and onkeydown I sent the key pressed to the update function in the sprite class.
Now for the sprite class there isn't something special:
public class Sprite {
enum State
{
Walking
}
State mCurrentState = State.Walking;
int mDirection = 0;
int mSpeed = 0;
int mPreviousKeyboardState;
private String spriteName;
Bitmap sprite;
int SPRITE_SPEED = 5;
int MOVE_LEFT = -1;
int MOVE_RIGHT = 1;
private float mScale = 1.0f;
Point Position;
public Sprite(String name,Bitmap sprite) {
this.sprite=sprite;
this.spriteName=name;
Position=new Point(150,150);
}
public void Update(int keyboard)
{
int aCurrentKeyboardState = keyboard;
UpdateMovement(aCurrentKeyboardState);
mPreviousKeyboardState = aCurrentKeyboardState;
}
private void UpdateMovement(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
mSpeed = 0;
mDirection = 0;
if (aCurrentKeyboardState==KeyEvent.KEYCODE_A)
{
mSpeed = SPRITE_SPEED;
mDirection = MOVE_LEFT;
}
else if(aCurrentKeyboardState==KeyEvent.KEYCODE_D)
{
mSpeed = SPRITE_SPEED;
mDirection= MOVE_RIGHT;
}
Position.x += mDirection * mSpeed;
}
}
public void Draw(Canvas c)
{
c.drawBitmap(sprite, Position.x,Position.y, null);
}
}
I just change the position of the image and move it depending on the key pressed.
Now here is the problem:
Using handler and invalidate was the only option I was able to find to replace "Game time" that appears in game engines, and although it works, it works very choppily, if the speed of the player is high it looks like it jumps pixels and if its low the animation is blurry and very slow, it looks like the invalidate takes more time and it happens not every 0.001 seconds but 0.5 seconds or so.
Here is how it looks like:
Slow speed (blurry and very slow):
Faster Speed (choppy not smooth):
Is there a better way to do it, again with only using what android offers?
Threads! However the handler is not the root of your problem judging by how slow your animation is running and how choppy the fast one is, you are probably using a canvas tied into an ImageView? This is not very fast at all. You should look into using a SurfaceView (works with lower APIs but not the fastest) or into TextureView (super fast, I had to delay my thread cause the animation was just a blur). Both of these rely on canvas at their core.
There are lots of examples out there on in internets on how to code these and you can adapt them for your purposes. To give you a place to start you can look HERE at some samples I wrote.
how to perform single touch on isActionMove() because when i move finger on sprites it takes multipal touch events and update scores twice thrice
mHardware[active] = new Sprite(pX, pY, java, this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float X, float Y) {
if (pSceneTouchEvent.isActionMove()) {
score++;
}
}
};
i cant use isActionDown because its a game like fruit ninja in which i need to move finger across screen
now problem is score is sometimes increasse by 2 sometimes by 3 because when i move finger on sprite application notices several short movements in place of one
you should use
private static boolean isFirstMove;
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float X, float Y) {
if (pSceneTouchEvent.isActionDown()) {
isFirstMove = true;
}
if (pSceneTouchEvent.isActionMove()) {
if(isFirstMove) {
score++;
isFirstMove = false;
}
}
if (pSceneTouchEvent.isActionUp()) {
isFirstMove = false;
}
});
If you found some what above answer correct for you then I have some suggestion in this.
You have to implement both scene and area touch event for your game scene.
SceneTouch event method contains two events isActionDown() and isActionUp() like in the following code.
public void onSceneTouchEvent(...){
if(pSceneTouchEvent.isActionDown()){
isFirstTouch=true;
return true;
} else if(pSceneTouchEvent.isActionUp()){
isFirstTouch=false;
return true;
}
return false;
}
Area Touch method contains only single event isActionMove() like in the following code.
public void onAreaTouch(...){
if(pSceneTouchEvent.isActionMove()){
if(isFirstMove) {
score++;
isFirstMove = false;
}
return true;
}
return false;
}
You have to follow above strategy because some time desire event not occur for your sprite so you don't get your desire result.
solution given by julien dumortier is working perfectly
static boolean isFirstMove=true;
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float X, float Y) {
if (pSceneTouchEvent.isActionMove()) {
if(isFirstMove) {
score++;
isFirstMove = false;
}
}
});
when i touch finger on sprite, score increses randomly not by fix rate i mean that i set score
to increase 50 each time but when i scroll on sprite sometimes it increases by 100 sometimes by 150 and 200;
mHardware1[active] = new Sprite(pX, pY, samsung,
this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float X, float Y) {
if (pSceneTouchEvent.isActionMove()) {
scene.detachChild(mHardware1[active]);
score+50;
}
it works when i use isActionDown in place of isActionMove but m working a game like fruit ninja in which i need to scroll finger on screen that why i cant use isActionDown
You can use a SurfaceScrollDetector, which detects when the user is sliding his finger across the screen. It has the following events associated with it:
onScrollStarted
onScroll
onScrollFinished
I guess you could increase by 50 when you reach the onScrollFinished.
I am currently using the SurfaceScrollDetector for a project, but I haven't used it in a way you are asking about, so I can't say forsure if it will work as expected.
Here is one of the examples that uses it (in addition to the PinchZoomDetector):
https://github.com/nicolasgramlich/AndEngineExamples/blob/GLES2/src/org/andengine/examples/PinchZoomExample.java
Scene updates happen on a different thread to UI events, so possibly multiple queued touchscreen events are getting through before the event handler realises that the sprite has been detached.
Set a local boolean variable to prevent this, e.g.:
boolean touchProcessed = false;
mHardware1[active] = new Sprite(pX, pY, samsung,
this.getVertexBufferObjectManager());
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float X, float Y) {
if (!touchProcessed & pSceneTouchEvent.isActionMove()) {
touchProcessed = true;
scene.detachChild(mHardware1[active]);
score += 50;
}
}
Note that you can use: mHardware1[active].detachSelf() instead of scene.detachChild(...).
Also note that you should be detaching in the sprite in the update thread, thus:
boolean touchProcessed = false;
mHardware1[active] = new Sprite(pX, pY, samsung,
this.getVertexBufferObjectManager());
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float X, float Y) {
if (!touchProcessed & pSceneTouchEvent.isActionMove()) {
touchProcessed = true;
score += 50;
engine.runOnUpdateThread(new Runnable() {
#Override
public void run() {
mHardware1[active].detachSelf();
}
});
}
}