My animation is not working, only a static picture is displayed. I did everything according to the example from libgdx/wiki. Why does not it work?
public class Thorns extends GameObject implements IGameObject {
Animation<TextureRegion> animation;
private static final int FRAME_COLS = 1, FRAME_ROWS = 2;
public Thorns(Texture texture, Body body) {
super(texture, body,false);
Texture walkSheet = new Texture("Thorns.png");
TextureRegion[][] tmp = TextureRegion.split(walkSheet,
walkSheet.getWidth() / FRAME_COLS,
walkSheet.getHeight() / FRAME_ROWS);
TextureRegion[] walkFrames = new TextureRegion[FRAME_ROWS*FRAME_COLS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < FRAME_COLS; j++) {
walkFrames[index++] = tmp[i][j];
}
}
animation = new Animation<TextureRegion>(1.025f, walkFrames);
}
#Override
public void dispose() {
}
int stateTime;
#Override
public void draw(SpriteBatch spriteBatch) {
stateTime += Gdx.graphics.getDeltaTime();
TextureRegion currentFrame = (TextureRegion) animation.getKeyFrame(stateTime, false);
spriteBatch.draw(currentFrame, body.getTransform().getPosition().x, body.getTransform().getPosition().y);
//drawSprite(spriteBatch);
}
}
Animation does not start at all
Quite possible animation is running but you're not getting his view, because you've two frame animation with frame duration 1.025 sec. And your Animation is running without loop.
Try looped Aniamation so pass true as in second parameter of getKeyFrame (float stateTime, boolean looping) method.
#Override
public void draw(SpriteBatch spriteBatch) {
stateTime += Gdx.graphics.getDeltaTime();
TextureRegion currentFrame = animation.getKeyFrame(stateTime, true);
spriteBatch.draw(currentFrame, body.getTransform().getPosition().x, body.getTransform().getPosition().y);
}
EDIT
Change data type of stateTime to float from int.
Related
I am making a game with android. The player is a rectangle that has to jump over obstacles. When i jump i decrease the height and the y coordinates. When i run the game the rectangle is jumping but when i try to jump over an obstacle its still hitting it. So i think i forget to change a value but i have no idea what value. Sorry for my bad english and i am a beginner at coding.
This is my Player class:
package com.example.niek.speelveld;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* Created by Niek on 15-8-2017.
*/
public class Player extends GameObject {
private int score;
private boolean up;
private boolean playing;
private long startTime;
private int h = 0;
private boolean jump;
public Player(int x , int y){
super.x = x;
super.y = y;
width = 100;
height = GamePanel.HEIGHT;
score = 0;
startTime = System.nanoTime();
}
public void setUp(boolean b){up = b;}
public void update(){
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100){
score++;
startTime = System.nanoTime();
}
if(up && h == 0){
jump = true;
up = false;
}
if (jump) {
if (h < 120) {
h = h + 7;
height = height - 7;
y = y - 7;
} else {
jump = false;
}
} else {
if (h > 0) {
h = h - 7;
height = height + 7;
y = y + 7;
}
}
}
public void draw(Canvas canvas){
Paint myPaint = new Paint();
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(7);
canvas.drawRect(x, y, width + x, height, myPaint );
myPaint.setStrokeWidth(1);
canvas.drawText("HIGHSCORE " + score, GamePanel.WIDTH - 100 , 0+myPaint.getTextSize(), myPaint);
}
public int getScore(){return score;}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
//public void resetScore(){score = 0;}
public boolean getJump() {
return jump;
}
}
And in my Gamepanel class i use these 2 methods. When i call the class obstacle.get(i).update(); its only updating the x value so its moving towards the player.
public void update(){
if(player.getPlaying()) {
bg.update();
player.update();
//Add obstacles with timer
long obstacleElapsed = (System.nanoTime()-obstacleStartTime)/1000000;
if(obstacleElapsed >(2000 - player.getScore()/4)){
obstacles.add(new Obstacle(BitmapFactory.decodeResource(getResources(), R.drawable.rsz_spike1), WIDTH + 10, HEIGHT - 51, 14, 51, player.getScore()));
//reset timer
obstacleStartTime = System.nanoTime();
}
}
//Loop through every obstacle and check collision
for(int i = 0; i<obstacles.size(); i++){
obstacles.get(i).update();
if (collision(obstacles.get(i), player)) {
obstacles.remove(i);
player.setPlaying(false);
Intent intent = new Intent(c, Result.class);
intent.putExtra("SCORE", player.getScore());
c.startActivity(intent);
break;
}
//Remove obstacles that are out of the screen
if (obstacles.get(i).getX() < -100) {
obstacles.remove(i);
break;
}
}
}
public boolean collision(GameObject o, GameObject p){
if(Rect.intersects(o.getRectangle(), p.getRectangle())){
return true;
}
return false;
}
#Override
public void draw(Canvas canvas){
//Get Width and Height from screen
final float scaleFactorX = (float)getWidth()/WIDTH;
final float scaleFactorY = (float)getHeight()/HEIGHT;
if(canvas!=null) {
final int savedState = canvas.save();
canvas.scale(scaleFactorX, scaleFactorY);
bg.draw(canvas);
player.draw(canvas);
//Draw obstacles
for(Obstacle o : obstacles ){
o.draw(canvas);
}
canvas.restoreToCount(savedState);
}
}
And finally the Player and the Obstacle class extends Gameobject where i have the getRectangle method.
public Rect getRectangle(){
return new Rect(x, y, x+width, y+height);
}
I have a animation which i want to flip to the left if key LEFT is pressed, but it doesnt stay flipped. It only flips like 1 frame then turns back again.
Here is my GameScreen where i draw everything:
public class GameScreen extends ScreenManager{
//For the view of the game and the rendering
private SpriteBatch batch;
private OrthographicCamera cam;
//DEBUG
private Box2DDebugRenderer b2dr;
//World, Player and so on
private GameWorld world;
private Player player;
private Ground ground;
//player animations
private TextureRegion currFrame;
public static float w, h;
public GameScreen(Game game) {
super(game);
//vars
w = Gdx.graphics.getWidth();
h = Gdx.graphics.getHeight();
//view and rendering
batch = new SpriteBatch();
cam = new OrthographicCamera();
cam.setToOrtho(false, w/2, h/2);
//debug
b2dr = new Box2DDebugRenderer();
//world, bodies ...
world = new GameWorld();
player = new Player(world);
ground = new Ground(world);
}
#Override
public void pause() {
}
#Override
public void show() {
}
#Override
public void render(float delta) {
//clearing the screen
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//updating
update(Gdx.graphics.getDeltaTime());
player.stateTime += Gdx.graphics.getDeltaTime();
//render
batch.setProjectionMatrix(cam.combined);
currFrame = Player.anim.getKeyFrame(Player.stateTime, true);
batch.begin();
batch.draw(currFrame, Player.body.getPosition().x * PPM - 64, Player.getBody().getPosition().y * PPM- 72);
batch.end();
//debug
b2dr.render(GameWorld.getWorld(), cam.combined.scl(PPM));
}
#Override
public void resize(int width, int height) {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
#Override
public void onKlick(float delta) {
}
public void update(float delta){
world.update(delta);
updateCam(delta);
Player.keyInput(delta);
System.out.println("X-POS" + Player.getBody().getPosition().x);
System.out.println("Y-POS" + Player.getBody().getPosition().y);
}
public void updateCam(float delta){
Vector3 pos = cam.position;
pos.x = Player.getBody().getPosition().x * PPM;
pos.y = Player.getBody().getPosition().y * PPM;
cam.position.set(pos);
cam.update();
}
}
and this is the Player class where the animation is:
public class Player {
public static Body body;
public static BodyDef def;
private FixtureDef fd;
//textures
public static Texture texture;
public static Sprite sprite;
public static TextureRegion[][] region;
public static TextureRegion[] idle;
public static Animation<TextureRegion> anim;
public static float stateTime;
//set form
private PolygonShape shape;
private GameScreen gs;
public Player(GameWorld world){
texture = new Texture(Gdx.files.internal("player/char_animation_standing.png"));
region = TextureRegion.split(texture, texture.getWidth() / 3, texture.getHeight() / 2);
idle = new TextureRegion[6];
int index = 0;
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j++){
sprite = new Sprite(region[i][j]);
idle[index++] = sprite;
}
}
anim = new Animation<TextureRegion>(1 / 8f, idle);
stateTime = 0f;
def = new BodyDef();
def.fixedRotation = true;
def.position.set(gs.w / 4, gs.h / 4);
def.type = BodyType.DynamicBody;
body = world.getWorld().createBody(def);
shape = new PolygonShape();
shape.setAsBox(32 / 2 / PPM, 64/ 2 / PPM);
fd = new FixtureDef();
fd.shape = shape;
fd.density = 30;
body.createFixture(fd);
shape.dispose();
}
public static Body getBody() {
return body;
}
public static BodyDef getDef() {
return def;
}
public static Texture getTexture() {
return texture;
}
public static void keyInput(float delta){
int horizonForce = 0;
if(Gdx.input.isKeyJustPressed(Input.Keys.UP)){
body.applyLinearImpulse(0, 300f, body.getWorldCenter().x, body.getWorldCenter().y, true);
//body.applyForceToCenter(0, 1200f, true);
System.out.println("PRESSED");
}
if(Gdx.input.isKeyPressed(Input.Keys.LEFT)){
horizonForce -= 1;
sprite.flip(!sprite.isFlipX(), sprite.isFlipY());
}
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)){
horizonForce += 1;
}
body.setLinearVelocity(horizonForce * 20, body.getLinearVelocity().y);
}
}
thank you in advance and any answer is appreciated :D
Your sprite variable contain only one frame at the time of pressing left key. So, it flip that current sprite of your animation frame.
To solve the Problem you have to flip all the animation frame on pressing the left key.
You're only flipping last frame of Animation by sprite reference, You need to flip all frames of your Animation anim. You can flip in this way :
if(keycode== Input.Keys.RIGHT) {
for (TextureRegion textureRegion:anim.getKeyFrames())
if(!textureRegion.isFlipX()) textureRegion.flip(true,false);
}
else if(keycode==Input.Keys.LEFT) {
for (TextureRegion textureRegion:anim.getKeyFrames())
if(textureRegion.isFlipX()) textureRegion.flip(true,false);
}
I am making a 2D game in Libgdx and when I try to make a player shoot every X seconds it crashes and that happens only if I call addBullet() inside a timer.
Here is code for Controller.class:
public class Controller {
private LinkedList<Bullet> b = new LinkedList<Bullet>();
private Bullet tempBullet;
private LinkedList<Zombie> z = new LinkedList<Zombie>();
private Zombie tempZombie;
private API api;
private Player p;
private World w;
public void create() {
api = new API();
w = new World();
p = new Player(100, 40);
Timer t = new Timer( );
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Crashes when this is executed
addBullet(new Bullet(p.getX() + p.getTex().getWidth(), p.getY() + p.getTex().getHeight()));
}
}, 500,2500);
}
public void tick() {
p.tick();
for(int i = 0; i < b.size(); i++){
tempBullet = b.get(i);
tempBullet.tick();
}
for(int i = 0; i < z.size(); i++){
tempZombie = z.get(i);
tempZombie.tick();
for(int j = 0; j < b.size(); j++){
tempBullet = b.get(j);
if(api.getCollisionBox(tempZombie.getX(), tempZombie.getY(), tempZombie.getTex().getWidth(), tempZombie.getTex().getHeight(), tempBullet.getX(), tempBullet.getY(), 10, 10)){
tempZombie.damage();
b.remove(tempBullet);
if(tempZombie.getHealth() <= 0){
z.remove(tempZombie);
}
}
}
}
}
public void render() {
w.render(); // Mora biti na pocetku ove funkcije
p.render();
for(int i = 0; i < b.size(); i++){
tempBullet = b.get(i);
tempBullet.render();
}
for(int i = 0; i < z.size(); i++){
tempZombie = z.get(i);
tempZombie.render();
}
}
public void dispose() {
w.dispose();
p.dispose();
for(int i = 0; i < b.size(); i++){
tempBullet = b.get(i);
tempBullet.dispose();
}
for(int i = 0; i < z.size(); i++){
tempZombie = z.get(i);
tempZombie.dispose();
}
}
public void keyInput() {
//if(Gdx.input.isButtonPressed(Input.Keys.W))
}
public void mouseInput() {
//if(Gdx.input.isButtonPressed(Input.Buttons.LEFT))
if(Gdx.input.isTouched())
addBullet(new Bullet(p.getX() + p.getTex().getWidth(), p.getY() + p.getTex().getHeight()));
}
public void addBullet(Bullet block){
b.add(block);
}
public void removeBullet(Bullet block){
b.remove(block);
}
public void addZombie(Zombie block){
z.add(block);
}
public void removeZombie(Zombie block){
z.remove(block);
}
}
Here is the code for the bullet.class:
public class Bullet {
private Texture tex;
private SpriteBatch batch;
private int x;
private int y;
public Bullet(int x, int y){
this.x = x;
this.y = y;
batch = new SpriteBatch();
tex = new Texture(Gdx.files.internal(("bullet.png")));
}
public void tick(){
x += 10;
}
public void render(){
batch.begin();
batch.draw(tex, x, y, 100, 100);
batch.end();
}
public void dispose() {
tex.dispose();
batch.dispose();
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Without seeing the full exception, my guess is that there might be something wrong with the loading of the image.
ps. Why the extra brackets?
tex = new Texture(Gdx.files.internal(("bullet.png")));
One set of brackets is enough:
tex = new Texture(Gdx.files.internal("bullet.png"));
I want to make a game wherein when the main character sprite's X coordinate is less than the middle of the screen, he moves to the right and when it's more than the middle of the screen, he moves to the left. The sprite's animation changes when he is moving and when he is still (after reaching its destination). What I want to know is how can I do this when the sprite and its code for animation is in one class and the code for changing its X coordinate is in another class? Is it best to draw the same sprite in every class? How can I change the sprite when it is moving horizontally and when it is still? I plan to separate the code for what the sprite's actions will be in different classes because i want to call them randomly. Here is my code for the sprite's animation and i have no class for changing the x coordinate yet :
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.jpfalmazan.ninjaassault.NinjaAssault;
public class MainScreen implements Screen {
private static final int FRAME_COLS = 3;
private static final int FRAME_ROWS = 2;
Animation walkAnimation;
Texture walkSheet = new Texture ("ninjaWalk.png");
TextureRegion[] walkFrames;
TextureRegion currentFrame;
Texture holdStart;
float stateTime;
public Texture background;
private NinjaAssault game;
private Music BackgroundSFX;
public float screenWidth = Gdx.graphics.getWidth();
public float screenHeight = Gdx.graphics.getHeight();
float x = screenWidth/2;
float y = screenHeight/2;
public float walkSheetWidth = walkSheet.getWidth();
public float walkSheetHeight = walkSheet.getHeight();
public MainScreen (NinjaAssault game){
this.game = game;
}
#Override
public void show(){
background = new Texture("BGBlue.png");
holdStart = new Texture ("HoldStart.png");
BackgroundSFX = Gdx.audio.newMusic(Gdx.files.internal("data/RADWIMPS-iindesuka.mp3"));
TextureRegion[][] tmp = TextureRegion.split(walkSheet, (int )walkSheetWidth/FRAME_COLS, (int) walkSheetHeight/FRAME_ROWS);
walkFrames = new TextureRegion[FRAME_COLS*FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++){
for (int j = 0; j < FRAME_COLS; j++) {
walkFrames[index++] = tmp[i][j];
}
}
walkAnimation = new Animation(0.0887f, walkFrames);
stateTime = 0f;
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stateTime += Gdx.graphics.getDeltaTime();
currentFrame = walkAnimation.getKeyFrame(stateTime, true);
float hsWidth = holdStart.getWidth();
float hsHeight = holdStart.getHeight();
float currentFrameWidth = (float)(screenHeight*0.15);
float currentFrameHeight = (float)(screenHeight*0.15);
float holdStartWidth = (float)(screenWidth * 0.75);
game.batch.begin();
game.batch.draw(background,0,0, screenWidth,screenHeight);
BackgroundSFX.play();
game.batch.draw(currentFrame, x -currentFrameWidth/2, 0,currentFrameWidth,currentFrameHeight);
game.batch.draw(holdStart, (screenWidth / 2 - (holdStartWidth / 2)), (float) (screenHeight * 0.5), holdStartWidth, holdStartWidth * (hsHeight / hsWidth));
game.batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
BackgroundSFX.dispose();
background.dispose();
walkSheet.dispose();
holdStart.dispose();
}
}
I tried to research on how to do this but the answers I get wasn't that helpful.
Simplest way is to create a Player class and put all the code for the animation and frames in there. Then give it a way to save its position. Like a vector or just a float for the x coordinate. Or even better, use a Rectangle. A rectangle will make moving and collision detection much easier.
Something like this:
public class Player{
private Animation walkAnimation;
private Texture walkSheet;
private TextureRegion[] walkFrames;
private TextureRegion currentFrame;
private float stateTime;
private Rectangle bound; //used for positioning and collision detection
public Player(float x, float y, float width, float height){
bound = new Rectangle();
bound.x = x;
bound.y = y;
bound.width = width;
bound.height = height;
walkSheet = new Texture ("ninjaWalk.png");
TextureRegion[][] tmp = TextureRegion.split(walkSheet,(int)walkSheetWidth/FRAME_COLS, (int) walkSheetHeight/FRAME_ROWS);
walkFrames = new TextureRegion[FRAME_COLS*FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++){
for (int j = 0; j < FRAME_COLS; j++) {
walkFrames[index++] = tmp[i][j];
}
}
walkAnimation = new Animation(0.0887f, walkFrames);
stateTime = 0f;
}
public rectangle getBound(){
return bound;
}
public void update(float delta){
statetime += delta;
currentFrame = walkAnimation.getKeyFrame(stateTime, true);
}
public TextureRegion getCurrentFrame(){
return currentFrame;
}
}
This is just a quick untested example.
You say you want to move the player from another class. I don't know how you plan to do that, but all you need to do to move the player is to manipulate the x and y of the bound.
Just some other comments on you code:
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
player.update(delta); // to update the player
/***
* This does not have to be set every single frame. Move it to show()
*
float hsWidth = holdStart.getWidth();
float hsHeight = holdStart.getHeight();
float currentFrameWidth = (float)(screenHeight*0.15);
float currentFrameHeight = (float)(screenHeight*0.15);
float holdStartWidth = (float)(screenWidth * 0.75);
****************************************************/
BackgroundSFX.play(); // I am sure you don't need to start playing this every single frame? 60 times a second.
game.batch.begin();
game.batch.draw(background,0,0, screenWidth,screenHeight);
game.batch.draw(player.getCurrentFrame(), player.getBound().x, player.getbound().y, player.getBound().width, player.getBound().height)
game.batch.draw(holdStart, (screenWidth / 2 - (holdStartWidth / 2)), (float) (screenHeight * 0.5), holdStartWidth, holdStartWidth * (hsHeight / hsWidth));
game.batch.end();
}
I have a sprite that collides with obstacle, but i have a problem with the score in the top of my screen.
In the update of my class, The collisions are specified by an array, but when it collides with an object, the score is still growing and I can not stop it. this is my code:
private Array<Polen> polen;
private Score score;
public PlayState(GameStateManager gsm) {
super(gsm);
score = new Score(110, 310);
polen = new Array<Polen>();
for(int i = 1; i <= COUNT; i++){
polen.add(new Polen(i * (Polen.WIDTH)));
}
}
#Override
public void update(float dt) {
handleInput();
for(int i = 0; i < polen.size; i++){
Polen pol= polen.get(i);
if(pol.collides(aliado.getBounds())) {
pol.changeExplosion();
flagScore = 1;
}
if (pol.collides(aliado.getBounds())==false){
flagScore = 0;
}
}
if (flagScore == 1){
Score.count++;
flagScore=0;
//auxCount = Score.count +1;
}
score.update(dt);
updateGround();
cam.update();
}
Score Class:
public class Score {
private static final int MOVEMENT = 70;
private Vector3 position;
private Vector3 velocity;
private Rectangle bounds;
private Texture texture;
public Score(int x, int y){
position = new Vector3(x, y, 0);
velocity = new Vector3(0, 0, 0);
texture = new Texture("score0.png");
bounds = new Rectangle(x, y, ((texture.getWidth())), texture.getHeight());
}
public void update(float dt){//code for move the score for top of screen:
if(position.y > 0)
velocity.add(0, 0, 0);
velocity.scl(dt);
position.add(MOVEMENT * dt, velocity.y, 0);
if(position.y < 0)
position.y = 0;
velocity.scl(1/dt);
bounds.setPosition(position.x, position.y);
}
public Vector3 getPosition() {
return position;
}
public Texture getTexture() {
return texture;
}
public void setTexture(Texture texture) {
this.texture = texture;
}
public Vector3 getVelocity() {
return velocity;
}
public void setVelocity(Vector3 velocity) {
this.velocity = velocity;
}
public Rectangle getBounds(){
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public void dispose(){
texture.dispose();
}
}
In pol.changeExplosion() you should add a boolean to mark the object as done.
public class Polen {
private boolean exploded = false;
public void changeExplosion() {
// ...
exploded = true;
// ...
}
public boolean isExploded() {
return exploded;
}
}
Then, in your update function you can use this flag to determine if the score should stop being incremented.
for(int i = 0; i < polen.size; i++) {
Polen pol= polen.get(i);
if(pol.collides(aliado.getBounds()) && !pol.isExploded()) {
pol.changeExplosion();
flagScore = 1;
}
else if (!pol.collides(aliado.getBounds())) {
flagScore = 0;
}
}