I'm pretty new in LibGDX and Android Studio.
I'm trying to create a simple animation using 8 png files, the animation happens but it's so fast and unrealistic.
Is there a way to put a delay between frames?.
Thanks.
public class Runningrabbit extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture[] rabbits;
int rabbitState = 0;
float stateTime;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("back.png");
rabbits = new Texture[8];
rabbits[0] = new Texture("rabbit1.png");
rabbits[1] = new Texture("rabbit2.png");
rabbits[2] = new Texture("rabbit3.png");
rabbits[3] = new Texture("rabbit4.png");
rabbits[4] = new Texture("rabbit5.png");
rabbits[5] = new Texture("rabbit6.png");
rabbits[6] = new Texture("rabbit7.png");
rabbits[7] = new Texture("rabbit8.png");
stateTime = 0f;
}
#Override
public void render () {
if (rabbitState == 0) {
rabbitState = 1;
} else if (rabbitState == 1) {
rabbitState = 2;
} else if (rabbitState == 2) {
rabbitState = 3;
} else if (rabbitState == 3) {
rabbitState = 4;
} else if (rabbitState == 4) {
rabbitState = 5;
} else if (rabbitState == 5) {
rabbitState = 6;
} else if (rabbitState == 6) {
rabbitState = 7;
} else if (rabbitState == 7) {
rabbitState = 0;
}
batch.begin();
batch.draw(background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(rabbits[rabbitState], 200, 200);
batch.end();
}
}
You need to have the changing of the animation's state depend on time.
for example,
float accumulator = 0f;
...
public void render(){
float dt = Gdx.graphics.deltaTime(); //dt is the number of seconds that have passed in between each frame
accumulator += dt;
if(accumulator > 1)//one second has passed{
rabbitState++;
accumulator -= 1;
}
...
now, the animation will move forward once every second (which is painfully slow, but you can adjust then number).
Beyond your question, two things that I noticed looking through your code are:
You're making a new texture for each frame. Don't do this, have a texture with all the frames and make texture regions. There's no point in using a SpriteBatch if it needs to swap textures every single draw call.
There's an animation class in LibGDX as someone else has pointed out, it'll save you a lot of hassle to just use it.
You're manually changing the state with if statements when you just have to increment your index.
Related
So here I am a game developer who recently used unity and have almost given up on dealing with this stuff.
I'm currently working on a 2d platformer game.
And one that is left behind, the android control button.
I use "standard assets",
Unity's "CrossPlatformInput" to create the android controller I need.
And after being tested, it doesn't work at all to move the characters in the game.
I have followed the guide carefully and carefully many times, but the result is still the same
Can anyone help tell what happened?
this is the failing code i am using:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class Pemain : MonoBehaviour
{
public Rigidbody2D rb;
public float movespeed = 5f;
public int jumppower;
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool onGround;
private Animator anim;
private int facing;
void Start ()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
jumppower = 5;
facing = 1;
}
void FixedUpdate ()
{
onGround = Physics2D.OverlapCircle (groundCheck.position,groundCheckRadius,whatIsGround);
}
void Update () {
float move = CrossPlatformInputManager.GetAxis("Horizontal");
if (Input.GetKey(KeyCode.LeftArrow))
{
rb.velocity = new Vector2 (-movespeed, rb.velocity.y);
anim.SetBool ("Walking", true);
if (facing == 1)
{
transform.localScale = new Vector3 (-1f, 1f, 1f);
facing = 0;
}
} else if (Input.GetKey(KeyCode.RightArrow))
{
rb.velocity = new Vector2(movespeed, rb.velocity.y);
anim.SetBool ("Walking", true);
if (facing == 0)
{
transform.localScale = new Vector3 (1f, 1f, 1f);
facing = 1;
}
} else
{
anim.SetBool ("Walking", false);
}
if (Input.GetKey(KeyCode.Space) && onGround)
{
rb.velocity = new Vector2 (rb.velocity.x,jumppower);
}
}
}
You're not using the move variable at all in your code. So the CrossPlatformInput can't take any influence on the movement of your character. You should change the code to something similar to this.
float move = CrossPlatformInputManager.GetAxis("Horizontal");
if (move < -0.01f)
{
rb.velocity = new Vector2 (-movespeed, rb.velocity.y);
anim.SetBool ("Walking", true);
if (facing == 1)
{
transform.localScale = new Vector3 (-1f, 1f, 1f);
facing = 0;
}
} else if (move > 0.01f)
{
rb.velocity = new Vector2(movespeed, rb.velocity.y);
anim.SetBool ("Walking", true);
if (facing == 0)
{
transform.localScale = new Vector3 (1f, 1f, 1f);
facing = 1;
}
}
You might also want to brush up on your C# skills, as learning Unity and programming at the same time is very difficult.
I am drawing on screen but what is drawn doesn't match where the mouse is. I am already using unproject to change screen cords to world cords. I am using fill viewport, I think the drawing is not scaled up to current screen size maybe?
public void setPoint(float x , float y) {
mPoints.get(currentPointIndex).set(x,y,0);
if (x != 0 && y != 0) {
getCamera().unproject(mPoints.get(currentPointIndex));
}
}
public void render(float delta) {
super.render(delta);
for(int i=0; i < maxPoints-1; i++) {
Vector3 pnt = mPoints.get(i);
Vector3 lastPnt = null;
if(i>0) lastPnt = mPoints.get(i-1);
if(pnt.x == 0 && pnt.y == 0) continue;
Vector3 pnt2 = mPoints.get(i+1);
if(pnt2.x == 0 && pnt2.y == 0) continue;
drawLine(sb,pnt,pnt2,lineWidth,lineTex,colors.get(i));
}
}
public UiScreen(WriteGame game, ScreenType screenType) {
super(game, screenType);
FitViewport sc = new FitViewport(LAYOUT_HEIGHT,LAYOUT_HEIGHT);
//sc.update(LAYOUT_HEIGHT,LAYOUT_HEIGHT,true);
mStage = new Stage(sc);
mStageCamera = new OrthographicCamera();
sc.setCamera(mStageCamera);
mInputMultiplexer = new InputMultiplexer();
mInputMultiplexer.addProcessor(mStage);
mGame = game;
}
I am making a game where there there are frogs hopping around the screen. Once a frog is touched, I change the game image to what I have set as "deadFrog" and its movement stops. I have them all created under and array-list, and I am unsure as to how to only make changes to the individual frog. Right now, if one frog is tapped, all of the frogs stop moving and change to deadFrog. Hopefully you can help me fix the tactical nuke of a tap ;) *If you need any more information, just comment and I'll be sure to provide it!
Edit Is there not a way to access a single element in the blocks arraylist? I've tried doing blocks(1) for example but that's invalid.
Here is where the frogs are declared:
public void init() {
blocks = new ArrayList<Block>();
for (int i = 0; i < 5; i++) {
Block b = new Block(i * 200, MainActivity.GAME_HEIGHT - 95,
BLOCK_WIDTH, BLOCK_HEIGHT);
blocks.add(b);
tapped = false;
}
}
They are rendered with this:
private void renderFrogs(Painter g) {
if (!tapped) {
for (int i = 0; i < blocks.size(); i++) {
Block b = blocks.get(i);
if (b.isVisible()) {
Assets.runAnim.render(g, (int) b.getX(), (int) b.getY());
}
}
}
if (tapped) {
for (int i = 0; i < blocks.size(); i++) {
Block b = blocks.get(i);
if (b.isVisible()) {
g.drawImage(Assets.deadfrog, (int) b.getX(), (int) b.getY());
}
}
}
}
And this is the onTouchListener:
public boolean onTouch(MotionEvent e, int scaledX, int scaledY) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
recentTouchY = scaledY;
} else if (e.getAction() == MotionEvent.ACTION_UP) {
for (int i = 0; i < blocks.size(); i++) {
Block b = blocks.get(i);
if ((scaledY >= b.getY() - BLOCK_HEIGHT || scaledY <= b.getY()) && (scaledX >= b.getX() || scaledX <= b.getX() + BLOCK_WIDTH)) {
tapped = true;
}
}
}
return true;
}
Of course all frogs turn dead, you are supposed to keep "tapped" variable for each frog, your tapped variable is for all frogs at once.
Declare a class
public class Frog extends View{
public Drawable liveFrog;
public Drawable deadFrog;
public boolean isDead;
public Point location;
public int width;
public int height;
public Frog(Context context, int x, int y,int width,int height){
super(context);
this.isDead = false;
this.location = new Point(x,y);
this.width = width;
this.height = height;
}
public void onDraw(Canvas c){
super.onDraw(c);
if(!isDead){
//draw live frog at x,y
}else {
//draw dead frog at x,y
}
}
}
then you array is supposed to contain frogs
public void init(Context context) {
blocks = new ArrayList<Frog>();
for (int i = 0; i < 5; i++) {
Frog b = new Frog(context,i * 200, MainActivity.GAME_HEIGHT - 95,
BLOCK_WIDTH, BLOCK_HEIGHT);
blocks.add(b);
}
}
private void renderFrogs() {
for(Frog f : blocks){
//cause redraw
f.invalidate();
}
}
here comes the fun part, when you tap the frog
public boolean onTouch(MotionEvent e, int scaledX, int scaledY) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
recentTouchY = scaledY;
} else if (e.getAction() == MotionEvent.ACTION_UP) {
for (int i = 0; i < blocks.size(); i++) {
Frog frog = blocks.get(i);
if ((scaledY >= frog.getY() - BLOCK_HEIGHT || scaledY <= frog.getY()) && (scaledX >= frog.getX() || scaledX <= frog.getX() + BLOCK_WIDTH)) {
frog.isDead = true;
//cause one frog redraw
frog.invalidate();
//if the event was handled, stop here (unless you can have multiple frogs one on top of the other ?
return true;
}
}
}
//if the event was not handled, let it bubble up
return false;
}
From what I can see, your "tapped" boolean is not a property of EACH frog. It is declared once, and when triggered, per your for loop, will make every frog dead (obviously, since that's what you're experiencing).
Once "tapped" is true, your for loop is going through every block and assigning a dead frog to it.
I think you need to create a Frog class, and store instances of those in your ArrayList. A variable of the new frog class will be "touched", and when that is triggered you will do something to that specific instance only.
So here is my code,
public class GameView extends SurfaceView {
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Sprite> sprites = new ArrayList<Sprite>();
private long lastClick;
public int d = 0;
public int color;
TextView tv;
public int score;
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int arg2, int height) {
}
});
}
private void createSprites() {
int c = 10;
{
Random rnd = new Random();
color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256),
rnd.nextInt(256));
for (int b = 1; b <= c; b++) {
int random = (int) Math.ceil(Math.random() * 24);
if (random == 1) {
sprites.add(createSprite(R.drawable.bad1));
} else if (random == 2) {
sprites.add(createSprite(R.drawable.bad2));
} else if (random == 3) {
sprites.add(createSprite(R.drawable.bad3));
} else if (random == 4) {
sprites.add(createSprite(R.drawable.bad4));
} else if (random == 5) {
sprites.add(createSprite(R.drawable.bad5));
} else if (random == 6) {
sprites.add(createSprite(R.drawable.bad6));
} else if (random == 7) {
sprites.add(createSprite(R.drawable.bad7));
} else if (random == 8) {
sprites.add(createSprite(R.drawable.bad8));
} else if (random == 9) {
sprites.add(createSprite(R.drawable.bad9));
} else if (random == 10) {
sprites.add(createSprite(R.drawable.bad10));
} else if (random == 11) {
sprites.add(createSprite(R.drawable.bad11));
} else if (random == 12) {
sprites.add(createSprite(R.drawable.bad12));
} else if (random == 13) {
sprites.add(createSprite(R.drawable.bad13));
} else if (random == 14) {
sprites.add(createSprite(R.drawable.bad14));
} else if (random == 15) {
sprites.add(createSprite(R.drawable.bad15));
} else if (random == 16) {
sprites.add(createSprite(R.drawable.bad16));
} else if (random == 17) {
sprites.add(createSprite(R.drawable.bad17));
} else if (random == 18) {
sprites.add(createSprite(R.drawable.good1));
} else if (random == 19) {
sprites.add(createSprite(R.drawable.good2));
} else if (random == 20) {
sprites.add(createSprite(R.drawable.good3));
} else if (random == 21) {
sprites.add(createSprite(R.drawable.good4));
} else if (random == 22) {
sprites.add(createSprite(R.drawable.good5));
} else if (random == 23) {
sprites.add(createSprite(R.drawable.good6));
} else if (random == 24) {
sprites.add(createSprite(R.drawable.good7));
}
}
}
}
private Sprite createSprite(int resource) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
return new Sprite(this, bmp);
}
#SuppressLint({ "WrongCall", "DrawAllocation" })
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(color);
Paint paint = new Paint();
paint.setColor(Color.CYAN);
canvas.drawText("SCORE " + score, 10, 10, paint);
for (Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
}
// this is the ontouch event to destroy the sprites and make the blood splat
// effect
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 200) {
lastClick = System.currentTimeMillis();
synchronized (getHolder()) {
float x = event.getX();
float y = event.getY();
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
if (sprite.isCollition(x, y)) {
{
if ((sprites).equals (R.drawable.bad1))
score = score + 5;
else if ((sprites).equals(R.drawable.bad2))
score = score + 5;
else if ((sprites).equals(R.drawable.bad3))
score = score + 5;
else if ((sprites).equals(R.drawable.bad4))
score = score + 5;
else if ((sprites).equals(R.drawable.bad5))
score = score + 5;
else if ((sprites).equals(R.drawable.bad6))
score = score + 5;
else if ((sprites).equals(R.drawable.bad7))
score = score + 5;
else if ((sprites).equals(R.drawable.bad8))
score = score + 5;
else if ((sprites).equals(R.drawable.bad9))
score = score + 5;
else if ((sprites).equals(R.drawable.bad10))
score = score + 5;
else if ((sprites).equals(R.drawable.bad11))
score = score + 5;
else if ((sprites).equals(R.drawable.bad12))
score = score + 5;
else if ((sprites).equals(R.drawable.bad13))
score = score + 5;
else
score = score - 5;
}
d++;
if (d >= 10) {
d = 0;
createSprites();
}
break;
}
}
}
}
return true;
}
}
What I am trying to do is get,
if ((sprites).equals(R.drawable.bad1))
score = score + 5;
To check to see if somewhere in this code,
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 200) {
lastClick = System.currentTimeMillis();
synchronized (getHolder()) {
float x = event.getX();
float y = event.getY();
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
Holds the value of one of the pics that are being deleted, but I am not sure how to code this properly. I am not sure if I need to place the pics into an array each time the randomizer runs or what but the code is taken from the "edu4java" tutorial from youtube.
I have the program on a loop as you can tell that I can delete the pics on touch and the score was right I just am not sure how to get the,
if ((sprites).equals(R.drawable.bad1))
score = score + 5;
To check to "see" the proper pic string. Do I need to check the array that the code "auto creates"? Is there a way to check and see what the value of a string is? Such as "seeing" what is actually being "held" by "sprite" or "sprites" ?
One problem is that you do not supply the source code for Sprite, but perhaps it looks like the code here? Given the code there, there is no neat solution to your problem with the class as it is.
So, how I would approach solving this problem is to add to each sprite a resource ID:
private Sprite createSprite(int resource) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
return new Sprite(this, bmp, resource);
}
Note that I add the extra resource parameter to the constructor. Furthermore, I would add to the Sprite class a method int Sprite.getResource(), so your collision detection code becomes:
if (sprite.isCollition(x, y))
{
if (sprite.getResource() == R.drawable.bad1)
score = score + 5;
else if (sprite.getResource() == R.drawable.bad2)
score = score + 5;
else ...
}
Note: this code is in no way optimal, but hopefully this will point you in the right direction to discover for yourself a better solution. Here in Stack Overflow we don't throw fishes, we teach people to fish.
You can't compare a bitmap with a resource Id, and actually trying to do it manually your self would end up in quiet exhaustive performance for a simple validation, what i would do and to keep it simple, i would create my own class that extends from Sprite, and in stead of passing the context and bitmap, i would pass the context and resource Id, then within this class i would decode the resource and keep a reference of the resource id, i would override the equal method from Sprites and use the reference used to create the object to do the comparison, this would be my class
public class MySprite extends Sprite{
private int bmpID;
public MySprite(Context context, int bmpID){
this.bmpID = bmpID;
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), bmpID);
super(context, bmp);
}
#Override
public boolean equals(Object o) {
if(!(o instanceof MySprite))return false;
return this.bmpID == MySprite.class.cast(o).getBmpId();
}
public int getBmpId(){
return bmpID;
}
}
This way i keep it as a simple int comparison, and most important you can use it to compare two objects of same bmpID, or something like what u wanted by doing this:
if ((sprites).getBmpId() == R.drawable.bad1))
score = score + 5;
Regards!
I want to move background with the bob(Android Game Character) moving for that I make a Dynamic object name Background
public static int BACKGROUND_MOVE=0;
public static int BACKGROUND_FALL=1;
public static final float BACKGROUND_MOVE_VELOCITY =3.5f;
public static float BOB_WIDTH =10.0f;
public static float BOB_HEIGHT =15.0f;
public static long startTime = 0;
public int state;
public float stateTime;
public BackGround(float x, float y)
{
super(x, y, BOB_WIDTH, BOB_HEIGHT);
state = BACKGROUND_MOVE;
stateTime = 0;
accel.set(0,-2);
velocity.y=3.5f;//55
}
public void update (float deltaTime)
{
//velocity.add(World.gravity.x, World.gravity.y * deltaTime);
velocity.add(accel.x * deltaTime,accel.y*deltaTime);
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
if (velocity.y > 0 && state==Bob.BOB_STATE_HIT)//BOB_STATE_HIT is bob running //condition
{
if (state != BACKGROUND_MOVE)
{
state = BACKGROUND_MOVE;
stateTime = 0;
}
}
if (velocity.y > 0 && state != Bob.BOB_STATE_HIT)
{
if (state != BACKGROUND_FALL)
{
state = BACKGROUND_FALL;
stateTime = 0;
}
}
// if (velocity.y < 0 && state == BOB_STATE_HIT)
// {
// if (state != BOB_STATE_JUMP) {
// state = BOB_STATE_JUMP;
// stateTime = 0;
// }
//}
//if (position.y < 0) position.x = World.WORLD_WIDTH;
//if (position.x > World.WORLD_WIDTH) position.x = 0;
stateTime += deltaTime;
}
public void move()
{
if(state==BACKGROUND_MOVE)
{
startTime=System.nanoTime()/1000000000;
// state = BACKGROUND_MOVE;
velocity.y = BACKGROUND_MOVE_VELOCITY;
stateTime = 0;
}
}
similar to bob I amke object in World class and make an ArrayList Add Backgroung into that arraylist and at time of drawing get from arraylist and draw it...but no any effect show simply screen show and cross the rangeand red screen shown...please anyone help..
/*---------------background cam------*/
this.bcam = new OrthographicCamera(FRUSTUM_WIDTH,FRUSTUM_HEIGHT);
this.bcam.position.set(FRUSTUM_WIDTH,FRUSTUM_HEIGHT, 0);
this.batch = batch;
public void renderBackground()
{
GLCommon gl = Gdx.gl;
gl.glClearColor(1, 0, 0, 1);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
bcam.update();
batch.setProjectionMatrix(bcam.combined);
batch.disableBlending();
batch.begin();
if (world.objbackground.state ==BackGround.BACKGROUND_MOVE)
batch.draw(Assets.mainbackgroundRegion, cam.position.x - FRUSTUM_WIDTH / 2, cam.position.y - FRUSTUM_HEIGHT / 2, FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
// else
// {
// batch.draw(Assets.touchbackgroundRegion, cam.position.x -
// FRUSTUM_WIDTH / 2, cam.position.y - FRUSTUM_HEIGHT / 2,
// FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
// if (elapsed == 5)
// changebackground = 0;
// }
batch.end();
}
Either you want to move the background with Bob (1) or you want to have a fixed background (2):
(1): Set background's position to Bob's (probably with an offset, you can do that in the update function of the world), render using batch.draw(......, background.position.x, background.position.y).
(2): Throw away your complicated update methods in the BackGround object and use the render method as you do now.
But honestly, your intentions and explanations are not very clear, try to improve on that!