I'm writing a "space invaders" style app and I needed to do the move stop repeat animation that is classic to the game. I got the processes to go one way, using the code below, however when I want to go back, there does not seem to be an easy way to do this. I think the easiest way to do it is to have something happen on the end animation event, however I cannot get the event to trigger, even when calling super.end();. I've looked around for a way to trigger the event manually but to no avail. The way I am doing this may be a little sketchy but it works well enough right now to try and make it work all the way.
public void start()
{
if(begin < end) //recursive end condition
{
int distance = interval + begin; //change the distance to be traveled
//create new animation to do part of the whole animation
ObjectAnimator anim = ObjectAnimator.ofFloat(toAnimate, property, begin,distance);
TimeInterpolator inter = new TimeInterpolator() //makes the animation move with only one frame
{
public float getInterpolation(float prog)
{
return Math.round(prog * 10) / 10;
}
};
anim.setInterpolator(inter);
anim.setDuration((long)(500));
anim.addListener(new AnimatorListener()
{
#Override
public void onAnimationStart(Animator animation){}
#Override
public void onAnimationEnd(Animator animation)
{
start(); //start the next part of the movement
}
#Override
public void onAnimationCancel(Animator animation){}
#Override
public void onAnimationRepeat(Animator animation){}
});
begin = begin + interval; //update end recursion value
anim.start(); //begin the animation
}
super.end(); //this doesn't work... rip
}
public void start()
{
if(begin < end) //recursive end condition
{
int distance = interval + begin; //change the distance to be traveled
//create new animation to do part of the whole animation
ObjectAnimator anim = ObjectAnimator.ofFloat(toAnimate, property, begin,distance);
TimeInterpolator inter = new TimeInterpolator() //makes the animation move with only one frame
{
public float getInterpolation(float prog)
{
return Math.round(prog * 10) / 10;
}
};
anim.setInterpolator(inter);
anim.setDuration((long)(500));
anim.addListener(new AnimatorListener()
{
#Override
public void onAnimationStart(Animator animation){}
#Override
public void onAnimationEnd(Animator animation)
{
begin += interval;
if(begin < end){
start(); //start the next part of the movement
}
else{
// Do something else
}
}
#Override
public void onAnimationCancel(Animator animation){}
#Override
public void onAnimationRepeat(Animator animation){}
});
anim.start(); //begin the animation
}
}
Related
In my game the kid is collecting fruits but if he hits the rock 3 times or time is up before collecting the required points, the kid will jump to the half of the screen then fall down and start fail music then move to game over screen but I have two problems here:
when time is up the boy jump to top and continue out of the screen not the bottom and the music of fail is slow and choppy.
when kid hits rock 3 times it start fail music well and jump to the center of screen and fall down out of the screen from bottom and this is very good then go to game over screen, but when i go back from game over screen,the music of the Play screen is not working:
here is the code :
public boolean Rockhit()
{
if(Rocks.isRock) {
rocknum--;
Hud.collectorLives(rocknum);
Rocks.isRock=false;
if (rocknum == 0)
return true;
else
return false;
}
else
Hud.collectorLives(rocknum);
return false;
}
public State getState()
{
//Gdx.app.log(Float.toString(b2body.getLinearVelocity().x),"hi");
if ((Hud.getTime()==0&& Hud.getScore()<(level*30)+50)) {
Fruits.manager.get("music/Backmusic.ogg", Music.class).stop();
collectoIsDead=true;
Filter filter = new Filter();
filter.maskBits = Fruits.NOTHING_BIT;
for (Fixture fixture : b2body.getFixtureList())
fixture.setFilterData(filter);
b2body.applyLinearImpulse(new Vector2(0, 5f), b2body.getWorldCenter(), true);
//b2body.applyLinearImpulse(new Vector2(0,-2.5f), b2body.getWorldCenter(), true);
Fruits.manager.get("music/fail.mp3", Sound.class).play();
return State.DEAD;
}
if ( Rockhit()) {
Fruits.manager.get("music/Backmusic.ogg", Music.class).stop();
collectoIsDead=true;
Filter filter = new Filter();
filter.maskBits = Fruits.NOTHING_BIT;
for (Fixture fixture : b2body.getFixtureList())
fixture.setFilterData(filter);
b2body.applyLinearImpulse(new Vector2(0, 5f), b2body.getWorldCenter(), true);
//b2body.applyLinearImpulse(new Vector2(0,-2.5f), b2body.getWorldCenter(), true);
Fruits.manager.get("music/fail.mp3", Sound.class).play();
return State.DEAD;
}
if((Hud.getTime()==0&& Hud.getScore()>=(level*30)+50)|| (Hud.getScore()>=(level*30)+50)) {
Fruits.manager.get("music/Backmusic.ogg", Music.class).stop();
Fruits.manager.get("music/cheering.mp3", Sound.class).play();
return State.SUCCESS;
}
this is the code of gameover screen:
public class GameOverScreen implements Screen {
private Viewport viewport;
private Stage stage;
private Fruits game;
private float level;
public GameOverScreen(Fruits game,float level)
{
this.level=level;
this.game=game;
viewport=new FitViewport(Fruits.V_WIDTH,Fruits.V_HIEGT,new OrthographicCamera());
stage=new Stage(viewport,((Fruits) game).batch);
Label.LabelStyle font = new Label.LabelStyle(new BitmapFont(), Color.WHITE);
Table table=new Table();
table.center();
table.setFillParent(true);//the table will take all the stage
Label gameOverLabel = new Label("Game Over",font);
Label playAgainLabel = new Label("Click Here",font);
table.add(gameOverLabel).expandX();
table.row();
table.add(playAgainLabel).expandX().padTop(10f);// make it bellow Game over text by 10 pixels
stage.addActor(table);
}
#Override
public void render(float delta) {
if(Gdx.input.isTouched()) {
game.setScreen(new Worlds(game,level));
dispose();
}
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
}
#Override
public void show() {
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
}
here where I am processing the state of the kid in the play screen:
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
kid.draw(batch);
if(gameOver())//24
{
gameisover=true;
globalcounter--;
Gdx.app.log(Float.toString(globalcounter), "counter");
if(globalcounter==0) {
game.setScreen(new GameOverScreen(game, level));
dispose();
}
}
if(gameisover==true) {
globalcounter--;
Gdx.app.log(Float.toString(globalcounter), "counter");
if (globalcounter == 0) {
game.setScreen(new GameOverScreen(game, level));
dispose();
}
}
if(nextLevel())
{
prefs = Gdx.app.getPreferences("levels");
String name=prefs.getString("level", " ");
if(name==" ") {
prefs.putString("level", Float.toString(level + 1));
prefs.flush();
}
else {
prefs.putString("level", Float.toString(level+1));
prefs.flush();
}
game.setScreen(new Celebration(game,level+1));
dispose();
}
}
public boolean gameOver()//25
{
if(player.currentState== Collector.State.DEAD )// will show the game over screen after 3 seconds
{
return true;
}
return false;
}
public boolean nextLevel()//25
{
if(player.currentState== Collector.State.SUCCESS)// will show the game over screen after 3 seconds
{
return true;
}
return false;
}
Well, to start off with, your structure is flawed.
Your getState does not just return a state. A lot of things are happening before you return a state. You should really move those things and do them AFTER you have changed state.
I don't see a State.PLAYING? You only have 2 states DEAD and SUCCESS
You stop your background music:
Fruits.manager.get("music/Backmusic.ogg", Music.class).stop();
But it looks like you never start it again.
I'm new in game programming and I'm building one with libgdx in Android Studio.
I want the score to be the same as the elapsed time in the PlayState.
How can I place it in the top right corner with the "score" label next to it?
Please help! I'm stucked!
This is a little bit of code I've made in the PlayState.
public class PlayState extends State {
private Texture bg;
private Texture ground;
long startTime;
public static BitmapFont font;
private int score;
private String scoreText;
public PlayState(GameStateManager gsm) {
super(gsm);
bg = new Texture("bg.png");
ground = new Texture("ground.png");
startTime = System.currentTimeMillis();
font = new BitmapFont(Gdx.files.internal("font.fnt"));
font.getData().setScale(.25f, .25f);
}
#Override
protected void handleInput() {
}
#Override
public void update(float dt) {
handleInput();
cam.update();
}
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(bg, cam.position.x - (cam.viewportWidth / 2), 0);
System.out.println("Score = " + ((System.currentTimeMillis() - startTime) / 100));
sb.end();
}
#Override
public void dispose() {
bg.dispose();
ground.dispose();
System.out.println("Play State Disposed");
}
}
In your xml, place a TextView in the top right corner. You can use a Handler so that you can update the time and UI concurrently. Here is something I am using now..
Your XML would look something like this
<TextView
android:id="#+id/txt_Timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp" />
I put that in my FrameLayout
In your activity you can launch the Timer by doing this...
//Define global variable for time elapse and TextView
private int timeElapsed = 0;
private TextView txt_Timer;
//In the onCreate method define
txt_Timer = (TextView) findViewById(R.id.txt_View);
txt_Timer.setText(Integer.toString(timeElapsed));
//Place this wheree
Handler handler = new Handler();
Runnable r = new Runnable() {
public void run() {
//Update and display
timeElapsed += 1;
txt_Timer.setText(Integer.toString(timeElapsed));
//Call this again in one second (1000 milliseconds)
handler.postDelayed(this, 1000);
}
};
You may want to declare the Runnable globally so you can access elsewhere in the class. And when you want to start the timer you can call....
handler.postDelayed(r, 1000);
If you want to pause the timer you can call....
handler.removeCallbacks(r);
I don't know if this will solve your problem but it should working, assuming you are in an activity. I never made a mobile game with libgdx...
Can you guys tell me how can I execute function updateTiles() ONLY after all nodes' actions in function slideTiles(String s) are finished? I tried adding some while loop but it freezes whole program. After running functions one after another the animations just don't show up.
public boolean ccTouchesEnded(MotionEvent event)
{
CGPoint location = CCDirector.sharedDirector().convertToGL(CGPoint.ccp(event.getX(), event.getY()));
x2=location.x; y2=location.y;
float diffY = y1-y2;
float diffX = x1-x2;
if (Math.abs(diffX)>Math.abs(diffY)&&diffX<0)
move="right";
else if (Math.abs(diffX)>Math.abs(diffY)&&diffX>=0)
move="left";
else if (Math.abs(diffX)<=Math.abs(diffY)&&diffY<0)
move="up";
else if (Math.abs(diffX)<=Math.abs(diffY)&&diffY>=0)
move="down";
int row=(int)(y1/TILE_SQUARE_SIZE);
int column=(int)(x1/TILE_SQUARE_SIZE);
slideTiles(move);
//wait for animations to finish
int sum=0;
boolean actionDone=false;
while (!actionDone)
{
for (CCNode c : tilesNode.getChildren())
{
sum+=c.numberOfRunningActions();
}
//String s=sum+"";
//statusLabel.setString(s);
if (sum==0){
actionDone=true;
break;
}
sum=0;
}
updateTiles();
return true;
}
//////
public void slideTiles(String move)
{
// Increment the moves label and animate the tile
CCBitmapFontAtlas moveslabel = (CCBitmapFontAtlas) getChildByTag(MOVES_LABEL_TAG);
moves++;
moveslabel.runAction(CCSequence.actions(
//CCDelayTime.action(0.25f),
CCScaleTo.action(0.2f, 6/5f),
//CCDelayTime.action(0.25f),
CCScaleTo.action(0.2f, 5/6f)
));
moveslabel.setString("Moves:\n " + CCFormatter.format("%03d", moves ));
if (move.equals("up"))
{
for (int start=NUM_COLUMNS; start<2*NUM_COLUMNS; start++)
for (int y=start; y<NUM_COLUMNS*NUM_ROWS; y+=NUM_COLUMNS)
{
if (tileNumbers[y]!=EMPTY)
{
for (int f=start-NUM_COLUMNS; f<y; f+=NUM_COLUMNS)
{
if (tileNumbers[f]==EMPTY)
{
//y->f
CGPoint moveTo = tilesNode.getChildByTag(f).getPosition();
CCMoveTo movetile = CCMoveTo.action(0.25f, moveTo);
CCSequence movetileSeq = CCSequence.actions(movetile);//CCCallFunc.action(this,"stopAction"));
tilesNode.getChildByTag(y).runAction(movetileSeq);
tileNumbers[f]=tileNumbers[y];
tileNumbers[y]=EMPTY;
break;
}
}
}
}
}
Edit: Is this kind of solution correct? It works surprisingly well.
public boolean ccTouchesEnded(MotionEvent event)
{
...
...
slideTiles(move);
float time = 0.25f+0.05f; //0.25f is time of moveTo action for each tile
CCDelayTime delay = CCDelayTime.action(time);
CCCallFunc cA = CCCallFunc.action(this, "updateTiles");
CCSequence se = CCSequence.actions(delay, cA);
runAction(se);
return true;
}
Generally, you shouldn't use while loop to wait in UI thread , it will cause big problem you have saw it.
You should use Thread to do this waiting job.
new Thread(new Runnable() {
#Override
public void run() {
while(true){
//here you wait forever doesn't matter the UI thread.
if(everythingDone) {//here to add your condition
new Handler().post(new Runable() {
#Override
public void run() {
//Here you can do what you want and will be done in UI Thread
}
});
}
}
}
}).start();
First of all, i'm trying to make a puzzle game with the same concept as this game,
LINK: http://www.youtube.com/watch?v=-b2LunJPXC0 (the title of the game is Siren Fantasia)
Where in the user will hold a single piece of item from the gameboard and the objects that is surrounding it will be rotated clockwise until the user releases it.
I want to imitate that, When the user holds the button, the action will continuously loop until the user releases it.
Heres a sample of the code that i have already made:
float delay = 2f;
button.addListener(new ClickListener() {
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
if(pointer == 0) {
Timer.schedule(new Task(){
#Override
public void run() {
int counter = 0;
do{
Timer.schedule(new Task() {
#Override
public void run() {
button2.setVisible(false);
}
}, delay);
Timer.schedule(new Task() {
#Override
public void run() {
button2.setVisible(true);
}
}, delay);
}while( counter >= 1 );
}
}, buttonDelay);
}
return false;
}
});
And the output ain't the one that i wanted it to be. When i hold button, the button2 doesn't set to visible(false) and visible(true). But when i kept holding it over and over again, it would sometimes work.
I really need help.
Thank you.
how do call fire method in every five seconds with libGdx ?
this is my Enemy class :
I wrote the following code, but it is wrong.
public class Enemy {
private List<Bullet> bullets;
private boolean isFire;
public Enemy(){
bullets=new ArrayList<Bullet>();
}
public void update(float delta) {
Gdx.app.log("State", "State Fire");
if(!isFire){
Gdx.app.log("State", "Fire");
fire();
}else{
Gdx.app.log("State", "No Fire");
}
}
private void fire() {
isFire=true;
bullets.add(new Bullet(5, 32));
Timer.schedule(new Task(){
#Override
public void run() {
reload();
}
}, getDelay());
}
private void reload(){
isFire=false;
}
private int getDelay() {
return 5;
}
public List<Bullet> getBullets(){
return bullets;
}
}
Is there a way to solve the problem? I have no idea
I can think of two solutions for that:
1) the render method gets executed in every X milliseconds. You can use that one.
__UPDATE__
Below code is from here
void render(float delta)
Called when the screen should render itself.
Parameters:
delta - The time in seconds since the last render.
in that method, you can add delta to figure out if it has been X milliseconds since the last time you did whatever you want to do. If so, you can do it again. If not just increment your counter. Here is what I mean.
double counter = 0;
void render(float delta){
if (counter >= 5.0){
counter = 0.0;
fireUpYourTimelyProcessHere();
} else {
counter = counter + delta;
}
...
// other rendering stuff
}
However Do not do things that take a long time to finish here, like making an HTTP request or something.
}
2) Or you can create start a regular thread and start it. But keep in mind to avoid any UI rendering on that thread.