I want my characters move once to nearby tiles with one key press, and be rendered within the movements, so their movements would be animated. But when I tried this, they just teleport to the target tiles with some weird shakings. I think the problem is the ptime/delta variable didn't work as I thought, but I can't tell why. Even when I set the condition to "if(ptime >= 200f)", those movements are the same.
Here are my codes:
public class Player{
private Texture img;
public Vector2 worldPos;
public Vector2 tileMapPos;
private float time;
private float ptime;
private boolean isArrived;
private float nowx, nowy;
public Player() {
img = new Texture("filepath")
worldPos = new Vector2(1, 164);
tileMapPos = new Vector2(9, 9);
time = 0.5f;
ptime = 0f;
isArrived = false;
}
public void render(SpriteBatch batch) {
batch.draw(img, worldPos.x, worldPos.y, 32, 32);
}
public void update(SpriteBatch batch, float delta) {
time += delta;
if (time >= 0.5f) {
move(batch, delta);
time = 0f;
}
private void move(SpriteBatch batch, float delta) {
if (Gdx.input.isKeyJustPressed(Input.Keys.W)) {
ptime += delta;
isArrived = false;
nowx = worldPos.x;
nowy = worldPos.y;
if (ptime >= 0.02f) {
worldPos.x -= 2;
worldPos.y += 1;
ptime = 0f;
}
if ((nowx - worldPos.x) == 16 && (worldPos.y - nowy) == 8) {
isArrived = true;
}
tileMapPos.x += 1;
} else if (Gdx.input.isKeyJustPressed(Input.Keys.A)) {
///
} else if (Gdx.input.isKeyJustPressed(Input.Keys.S)) {
///
} else if (Gdx.input.isKeyJustPressed(Input.Keys.D)) {
///
}
}
}
And this is in the game screen class:
batch.begin();
map.render(batch, delta);
player.update(batch, delta);
player.render(batch);
batch.end();
Related
I'm trying to make a doodle jump game and currently I cant find a way to make the still image change to leg image once it lands on the ground and then change back to still. It kind of does that for one side but not not for both. I've tried using nested if, but then it wouldn't detect the button press. Here's the code:
GameObject game;
PImage doodle;
void setup() {
size(640, 800);
smooth(4);
frameRate(10);
doodle = loadImage("https://i.imgur.com/ytwebph.png");
game = new Doodle(new PVector(width/2, height-doodle.height*2), doodle);
game.setWidthAndHeight(new PVector(width, height));
}
void draw() {
background(200);
game.display();
game.move();
}
void keyPressed() {
game.setMove(keyCode, true);
}
void keyReleased() {
game.setMove(keyCode, false);
}
protected class Doodle extends GameObject {
protected float velocityY, gravity, time;
protected float groundPosition;
protected int facing = 0; //0 = right; 1 = left
protected Doodle(PVector position, PImage picture) {
super(position, picture);
gravity = 20;
time = 0.4;
velocityY = 35*gravity*time;
super.setSpeed(10);
groundPosition = position.y - picture.height;
}
public void move() {
if (isRight || position.y < groundPosition) {
this.picture = doodleImg[0];
facing = 0;
} else if (isLeft || position.y < groundPosition) {
this.picture = doodleImg[2];
facing = 1;
}
position.x = position.x + speed*(int(isRight) - int(isLeft));
//border control
if (position.x+picture.width/2 <= 0) {
position.x = this.getWidthAndHeight().x-picture.width/2;
} else if (position.x+picture.width/2 >= this.getWidthAndHeight().x) {
position.x = 0-picture.width/2;
}
//jump
velocityY -= gravity * time;
position.y -= velocityY * time;
if (position.y > groundPosition) {
if (facing == 0) {
this.picture = doodleImg[1];
} else if (facing == 1) {
this.picture = doodleImg[3];
}
position.y = groundPosition;
velocityY = 35;
}
}
}
public class GameObject {
public PVector position, widthAndHeight;
public int size, speed;
public PImage picture;
public boolean isLeft, isRight;
public PImage[] doodleImg = new PImage[6];
public GameObject(PVector position, PImage picture) {
this.position = position;
this.picture = picture;
widthAndHeight = new PVector(0, 0);
speed = 1;
//0,1 right; 2,3 left; 4,5 shoot;
doodleImg[0] = loadImage("https://i.imgur.com/ytwebph.png");
doodleImg[1] = loadImage("https://i.imgur.com/Y0cFSFK.png");
doodleImg[2] = loadImage("https://i.imgur.com/FL3IhU5.png");
doodleImg[3] = loadImage("https://i.imgur.com/YuqWihj.png");
}
public void move() {
position.x = 0;
}
public void display() {
image(picture, position.x, position.y);
}
public boolean setMove(int keycode, boolean isPressed) {
switch(keycode) {
case LEFT:
return isLeft = isPressed;
case RIGHT:
return isRight = isPressed;
default:
return isPressed;
}
}
protected PVector getWidthAndHeight() {
return widthAndHeight;
}
void setSpeed(int speed) {
this.speed = speed;
}
public void setWidthAndHeight(PVector newWidthAndHeight) {
widthAndHeight = newWidthAndHeight;
}
}
First set the facing state, dependent on the isRight and isLeft:
if (isRight) {
facing = 0;
} else if (isLeft) {
facing = 1;
}
The set the image dependent on the state of facing and the vertical position position.y:
if (position.y < groundPosition) {
this.picture = doodleImg[facing==0 ? 0 : 2];
} else {
this.picture = doodleImg[facing==0 ? 1 : 3];
}
public void move() {
if (isRight) {
facing = 0;
} else if (isLeft) {
facing = 1;
}
if (position.y < groundPosition) {
this.picture = doodleImg[facing==0 ? 0 : 2];
} else {
this.picture = doodleImg[facing==0 ? 1 : 3];
}
position.x = position.x + speed*(int(isRight) - int(isLeft));
//border control
if (position.x+picture.width/2 <= 0) {
position.x = this.getWidthAndHeight().x-picture.width/2;
} else if (position.x+picture.width/2 >= this.getWidthAndHeight().x) {
position.x = 0-picture.width/2;
}
//jump
velocityY -= gravity * time;
position.y -= velocityY * time;
if (position.y > groundPosition) {
position.y = groundPosition;
velocityY = 35;
}
}
I am trying to make a game. I want the projectiles (balls) that I shoot to each have their own individual collisions with objects and the margins of the game screen, but right now when one ball collides with the game screen margins, every balls' velocity.x or velocity.y is multiplied by -1 to simulate collision rather than just the individual ball that hit's velocity being modified. (When one ball hits, all balls' velocities are affected). The projectiles are stored in an ArrayList in the GameWorld class and are all given an identical velocity when they are shot. You pick a direction to shoot in, then balls are shot every 0.3s in that direction until all balls are shot.
Here is the code from my Projectiles class:
package com.trimble.gameobjects;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;
import com.trimble.gameworld.GameWorld;
public class Projectile {
private Vector2 velocity, acceleration;
private Vector2 position;
private final float RADIUS = 3f;
private boolean active, shot;
private GameWorld world;
private float theta;
public Projectile(float x, GameWorld world) {
this.world = world;
this.position = new Vector2();
this.position.x = x;
this.position.y = world.getGameRect().y - 3;
// hitbox = new Circle(position, 3f);
this.velocity = new Vector2();
this.acceleration = new Vector2(0, 0.5f);
this.active = false;
this.shot = false;
}
public void update(float delta) {
if (active) {
position.add(velocity.cpy().scl(delta));
velocity.add(acceleration.cpy().scl(delta));
// left
if (this.position.x <= 3) {
Gdx.app.log("hit", " left");
this.position.x = 3;
this.velocity.x *= -1;
}
// right
else if (this.position.x >= world.getGameRect().width - 3) {
Gdx.app.log("hit", " right");
this.position.x = world.getGameRect().width - 3;
this.velocity.x *= -1;
}
// top
if (this.position.y < world.getGameRect().y + world.getGameRect().height + 3) {
Gdx.app.log("hit", " top");
this.position.y = world.getGameRect().y + world.getGameRect().height + 3;
this.velocity.y *= -1;
}
// bottom
else if (this.position.y > world.getGameRect().y - 3 && velocity.y > 0) {
Gdx.app.log("hit", " bottom");
if (!this.world.hasTouched()) {
this.world.getBaseCircle().setPositionX(position.x);
this.world.setTouched(true);
}
zeroVelocity();
this.active = false;
this.position = world.getBaseCirclePos();
this.world.addInactive();
}
}
}
public Vector2 getVelocity() {
return velocity;
}
public float getVelocityX() {
return velocity.x;
}
public float getVelocityY() {
return velocity.y;
}
public void setVelocity(Vector2 velocity) {
this.velocity = velocity;
}
public void setVelocityX(float x) {
this.velocity.x = x;
}
public void setVelocityY(float y) {
this.velocity.y = y;
}
public float getTheta() {
return theta;
}
public void setTheta(float theta) {
this.theta = theta;
}
public void zeroVelocity() {
this.velocity.x = 0;
this.velocity.y = 0;
}
public Vector2 getPosition() {
return position;
}
public void setPositionY(float y) {
this.position.y = y;
}
public void setPositionX(float x) {
this.position.x = x;
}
public void setPosition(Vector2 position) {
this.position = position;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public float getR() {
return RADIUS;
}
public boolean wasShot() {
return shot;
}
public void setShot(boolean shot) {
this.shot = shot;
}
}
Here is the code in GameWorld which is called when the player shoots:
public void transitionHasShot() {
if (currentState == GameState.READY) {
currentState = GameState.HASSHOT;
velocity.y = (float) (-165 * Math.sin(theta));
velocity.x = (float) (165 * Math.cos(theta));
baseCircle.setActive(false);
for (Projectile p : projectiles) {
p.setVelocity(velocity);
}
projectiles.get(0).setActive(true);
}
}
Let me know if you need any more info.
I solved the problem by changing the code in transitionHasShot():
change
for (Projectile p : projectiles) {
p.setVelocity(velocity);
}
to:
for (Projectile p : projectiles) {
p.setVelocity(velocity.cpy());
}
I'm trying to implement an autorotation method for a SpriteAnimation class (trying to port SpriteAnimation).
Everything is working, the sprite draws correctly (it uses the correct animations) it just doesn't rotate properly if at all, normally it seems to point to the origin (0, 0) only after its target matches its position while I want its rotation to update as it moves, i've tried both degrees and radians, neither of which work. It should be rotating to match the current direction it's going. I've been struggling with this for about a week now, but still have not gotten the desired result.
Full Code Here
Relevant code:
From SpriteAnimation
// The x position of the sprite's upper left corner pixel.
public int getX() { return (int)position.x; }
public void setX(int value)
{
prevPosition.x = position.x;
position.x = value;
updateRotation();
}
// The y position of the sprite's upper left corner pixel.
public int getY() { return (int)position.y; }
public void setY(int value)
{
prevPosition.y = position.y;
position.y = value;
updateRotation();
}
void updateRotation()
{
if (rotateByPosition)
{
Vector2 rotationVector = new Vector2(position.x - prevPosition.x, position.y - prevPosition.y);
rotationRad = rotationVector.angle();
rotationDeg = rotationRad * MathUtils.radiansToDegrees;
}
}
public void MoveBy(int x, int y)
{
prevPosition = new Vector2(position);
position.x += x;
position.y += y;
updateRotation();
}
public void Update(float deltaTime)
{
// Don't do anything if the sprite is not animating
if (animating)
{
// If there is not a currently active animation
if (getCurrentFrameAnimation() == null)
{
// Make sure we have an animation associated with this sprite
if (animations.size() > 0)
{
// Set the active animation to the first animation
// associated with this sprite
String[] sKeys = new String[animations.size()];
int index = 0;
for (Entry<String, FrameAnimation> mapEntry : animations.entrySet()) {
sKeys[index] = mapEntry.getKey();
index++;
}
setCurrentAnimation(sKeys[0]);
}
else
{
return;
}
}
// Run the Animation's update method
getCurrentFrameAnimation().Update(deltaTime);
// Check to see if there is a "follow-up" animation named for this animation
if (getCurrentFrameAnimation().getNextAnimation() != null && !getCurrentFrameAnimation().getNextAnimation().isEmpty())
{
// If there is, see if the currently playing animation has
// completed a full animation loop
if (getCurrentFrameAnimation().getPlayCount() > 0)
{
// If it has, set up the next animation
setCurrentAnimation(getCurrentFrameAnimation().getNextAnimation());
}
}
}
}
public void Draw(SpriteBatch spriteBatch, int xOffset, int yOffset)
{
updateRotation(); // Calling this while testing to make sure that it is being called
spriteBatch.draw(getCurrentTextureRegion(), getPosition().x + xOffset - center.x, getPosition().y + yOffset - center.y, center.x, center.y, getCurrentFrameAnimation().getFrameWidth(), getCurrentFrameAnimation().getFrameHeight(), 1.0f, 1.0f, rotationRad);
}
TestScreen class
package com.darkstudio.darkisle.screens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.darkstudio.darkisle.DarkIsle;
import com.delib.engine.sprite.MobileSprite;
/**
* Created by DarkEnder on 2017/06/27.
*/
public class TestScreen implements Screen {
final DarkIsle game;
OrthographicCamera camera;
Texture tankTexture;
MobileSprite mouseTank;
public TestScreen(final DarkIsle game)
{
this.game = game;
camera = new OrthographicCamera();
configureCamera();
tankTexture = new Texture(Gdx.files.internal("MulticolorTanks.png"));
mouseTank = new MobileSprite(tankTexture, 32, 32);
mouseTank.getSprite().AddAnimation("red", 0, 32, 32, 32, 8, 0.1f);
mouseTank.getSprite().AddAnimation("purple", 0, 128, 32, 32, 8, 0.1f, "red");
mouseTank.getSprite().AddAnimation("yellow", 0, 64, 32, 32, 8, 0.1f);
mouseTank.getSprite().setAutoRotate(true);
mouseTank.setPosition(new Vector2(100, 100));
mouseTank.setTarget(new Vector2(mouseTank.getPosition()));
mouseTank.setIsPathing(true);
mouseTank.setEndPathAnimation("yellow");
mouseTank.setLoopPath(false);
mouseTank.setSpeed(2);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
update();
game.batch.begin();
mouseTank.draw(game.batch);
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() {
}
private void configureCamera()
{
Vector3 camPos = new Vector3(camera.position);
float size = 800;
float cameraWidth = 0;
float cameraHeight = 0;
if (Gdx.graphics.getHeight() < Gdx.graphics.getWidth())
{
cameraWidth = size;
cameraHeight = size * Gdx.graphics.getHeight() / Gdx.graphics.getWidth();
}
else
{
cameraWidth = size * Gdx.graphics.getWidth() / Gdx.graphics.getHeight();
cameraHeight = size;
}
camera.setToOrtho(true, cameraWidth, cameraHeight);
camera.position.set(camPos.x + camera.viewportWidth / 2f, camPos.y + camera.viewportHeight / 2f, 0);
}
private void update() {
int xTouch = Gdx.input.getX(0);
int yTouch = Gdx.input.getY(0);
mouseTank.setTarget(xTouch, yTouch);
mouseTank.update(Gdx.graphics.getDeltaTime());
}
}
Edit: Just saying now that I've already tried using atan2 in MathUtils and it gave the same results.
The MobileSprite update method
public void update(float deltaTime)
{
if (active && movingTowardsTarget)
{
if ((target != null))
{
// Get a vector pointing from the current location of the sprite
// to the destination.
Vector2 Delta = new Vector2(target.x - sprite.getX(), target.y - sprite.getY());
if (Delta.len() > getSpeed())
{
Delta.nor();
Delta.scl(getSpeed());
getPosition().add(Delta);
}
else
{
if (target == sprite.getPosition())
{
if (pathing)
{
if (queuePath.size() > 0)
{
target = queuePath.remove();
if (loopPath)
{
queuePath.remove(target);
}
}
else
{
if (!(endPathAnimation == null))
{
if (!(getSprite().getCurrentAnimation() == endPathAnimation))
{
getSprite().setCurrentAnimation(endPathAnimation);
}
}
if (deactivateAtEndOfPath)
{
setIsActive(false);
}
if (hideAtEndOfPath)
{
setIsVisible(false);
}
}
}
}
else
{
sprite.setPosition(target);
}
}
}
}
if (active)
sprite.Update(deltaTime);
}
To get the radians angle:
void updateRotation()
{
if (rotateByPosition)
{
Vector2 rotationVector = new Vector2(position.x - prevPosition.x, position.y - prevPosition.y);
rotationRad = rotationVector.angleRad();
rotationDeg = rotationRad * MathUtils.radiansToDegrees;
}
}
and the draw method needs a degrees angle:
spriteBatch.draw(
getCurrentTextureRegion(),
getPosition().x + xOffset - center.x,
getPosition().y + yOffset - center.y,
center.x, center.y,
getCurrentFrameAnimation().getFrameWidth(), getCurrentFrameAnimation().getFrameHeight(),
1.0f, 1.0f,
rotationDeg
);
The screen mouse position is from the upper left corner the renderer needs from the bottom left corner:
int xTouch = Gdx.input.getX(0);
int yTouch = Gdx.graphics.getHeight() - Gdx.input.getY(0);
My app has 2 activities a main menu and a game play activity. you click play to start the game play and when you die you can click back to go to the main menu. For some reason when i click play for the third time (meaning ive died and went back to the main menu twice) the game crashes with this error.
FATAL EXCEPTION: main
Process: com.example.jordanschanzenbach.myapplication, PID: 1875
java.lang.OutOfMemoryError: Failed to allocate a 360012 byte allocation with 79976 free bytes and 78KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:700)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:535)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:558)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:588)
at com.example.jordanschanzenbach.myapplication.Obstacle.<init>(Obstacle.java:44)
at com.example.jordanschanzenbach.myapplication.ObstacleManager.populateObstacles(ObstacleManager.java:57)
at com.example.jordanschanzenbach.myapplication.ObstacleManager.<init>(ObstacleManager.java:38)
at com.example.jordanschanzenbach.myapplication.GamePlayScene.<init>(GamePlayScene.java:41)
at com.example.jordanschanzenbach.myapplication.GamePanel.<init>(GamePanel.java:29)
at com.example.jordanschanzenbach.myapplication.MainActivity.onCreate(MainActivity.java:27)
that's not the entire error message but i think i gave you what you needed. Now i tried to make an animation for the obstacles to be spikes instead of just black rectangles but for some reason the spikes will not display and i think it might correspond with the error i receive. But i don't understand why the spikes wont display as i used the same code for the animation for my player.
here is the code for my obstacle
public class Obstacle implements GameObject
{
private Rect rectangle;
private Rect rectangle2;
private int color;
private Animation falling;
private Animation fallingStill;
private Animation fallingAgain;
private AnimationManagerObstacle animationManagerObstacle;
public Rect getRectangle()
{
return rectangle;
}
public void IncrementY(float y )
{
rectangle.top += y;
rectangle.bottom += y;
rectangle2.top += y;
rectangle2.bottom += y;
}
public Obstacle(int rectHeight, int color, int startX, int startY, int playerGap)
{
this.color = color;
BitmapFactory bitfac = new BitmapFactory();
Bitmap fallings = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
Bitmap fallingStills = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
Bitmap fallingAgains = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
falling = new Animation(new Bitmap[]{fallings}, 2);
fallingStill = new Animation(new Bitmap[]{fallings, fallingStills}, 0.5f);
fallingAgain = new Animation(new Bitmap[]{fallings, fallingAgains}, 0.5f);
animationManagerObstacle = new AnimationManagerObstacle(new Animation[]{falling, fallingStill, fallingAgain});
rectangle = new Rect(0, startY, startX, startY + rectHeight);
rectangle2 = new Rect(startX + playerGap, startY, GlobalVariables.SCREEN_WIDTH, startY + rectHeight);
}
public boolean playerCollide(RectPlayer player)
{
return Rect.intersects(rectangle, player.getRectangle()) || Rect.intersects(rectangle2, player.getRectangle());
}
#Override
public void draw(Canvas canvas)
{
Paint paint = new Paint();
paint.setColor(color);
animationManagerObstacle.draw(canvas, rectangle);
canvas.drawRect(rectangle, paint);
canvas.drawRect(rectangle2, paint);
}
#Override
public void update()
{
animationManagerObstacle.update();
}
public void update(Point point)
{
float oldTop = rectangle.top;
rectangle.set(point.x - rectangle.width() / 2,
point.y - rectangle.height() / 2,
point.x + rectangle.width() / 2,
point.y + rectangle.height() / 2);
int state = 0;
if (rectangle.left - oldTop > 1)
{
state = 1;
}
else if (rectangle.left - oldTop < 2)
{
state = 2;
}
animationManagerObstacle.playAnim(state);
animationManagerObstacle.update();
}
}
this is the line that the error message points to
Bitmap fallings = bitfac.decodeResource(GlobalVariables.CURRENT_CONTEXT.getResources(), R.drawable.spikesupsidedown);
here is my obstacle manager where i add and display the obstacles
public class ObstacleManager
{
private ArrayList<Obstacle> obstacles;
private int playerGap;
private int obstacleGap;
private int obstacleHeight;
private int color;
private long startTime;
private long initTime;
private int score = 0;
public ObstacleManager(int playerGap, int obstacleGap, int obstacleHeight, int color)
{
this.playerGap = playerGap;
this.obstacleGap = obstacleGap;
this.obstacleHeight = obstacleHeight;
this.color = color;
startTime = initTime = System.currentTimeMillis();
obstacles = new ArrayList<>();
populateObstacles();
}
public boolean playerCollide(RectPlayer player)
{
for(Obstacle ob : obstacles)
{
if(ob.playerCollide(player))
return true;
}
return false;
}
private void populateObstacles()
{
int currY = -5 * GlobalVariables.SCREEN_HEIGHT / 4;
while(currY < 0)
{
int xStart = (int)(Math.random()*(GlobalVariables.SCREEN_WIDTH - playerGap));
obstacles.add(new Obstacle(obstacleHeight, color, xStart, currY, playerGap));
currY += obstacleHeight + obstacleGap;
}
}
public void update()
{
if (GlobalVariables.GAMEOVER)
{
for (int i = 0; i < 3; i++)
{
obstacles.remove(obstacles.size() - 2);
}
}
int elapsedTime = (int)(System.currentTimeMillis() - startTime);
startTime = System.currentTimeMillis();
float speed = (float)(Math.sqrt((1 + startTime - initTime) / 1750.0)) * GlobalVariables.SCREEN_HEIGHT /17500.0f;
for(Obstacle ob : obstacles)
{
ob.IncrementY(speed * elapsedTime);
}
if(obstacles.get(obstacles.size() - 1).getRectangle().top >= GlobalVariables.SCREEN_HEIGHT * 3/4)
{
int xStart = (int)(Math.random()*(GlobalVariables.SCREEN_WIDTH - playerGap));
obstacles.add(0, new Obstacle(obstacleHeight, color, xStart,
obstacles.get(0).getRectangle().top - obstacleHeight - obstacleGap, playerGap));
obstacles.remove(obstacles.size() - 1);
score++;
if (score > GlobalVariables.HIGHSCORE)
GlobalVariables.HIGHSCORE = score;
}
}
public void draw(Canvas canvas)
{
for(Obstacle ob : obstacles)
ob.draw(canvas);
Paint paint = new Paint();
paint.setTextSize(100);
paint.setColor(Color.RED);
canvas.drawText("" + score, 50, 50 + paint.descent() - paint.ascent(), paint);
canvas.drawText("HighScore: " + GlobalVariables.HIGHSCORE, GlobalVariables.SCREEN_WIDTH / 2 + 50, 50 + paint.descent() - paint.ascent(), paint);
}
}
here is my animation manager
public class AnimationManager
{
private Animation[] animations;
private int animationsIndex = 0;
public AnimationManager(Animation[] animations)
{
this.animations = animations;
}
public void playAnim(int index)
{
for (int i = 0; i < animations.length; i++)
{
if (i == index)
{
if (!animations[index].isPlaying())
{
animations[i].play();
}
}
else
{
animations[i].stop();
}
}
animationsIndex = index;
}
public void draw(Canvas canvas, Rect rect)
{
if (animations[animationsIndex].isPlaying())
{
animations[animationsIndex].draw(canvas, rect);
}
}
public void update()
{
if (animations[animationsIndex].isPlaying())
{
animations[animationsIndex].update();
}
}
}
and finally my animation class
public class Animation
{
private Bitmap[] frames;
private int frameIndex;
private boolean isPlaying = false;
public boolean isPlaying()
{
return isPlaying;
}
public void play()
{
isPlaying = true;
frameIndex = 0;
lastFrame = System.currentTimeMillis();
}
public void stop()
{
isPlaying = false;
}
private float frameTime;
private long lastFrame;
public Animation(Bitmap[] frames, float animTime)
{
this.frames = frames;
frameIndex = 0;
frameTime = animTime / frames.length;
lastFrame = System.currentTimeMillis();
}
public void draw(Canvas canvas, Rect destination)
{
if (!isPlaying)
return;
scaleRect(destination);
canvas.drawBitmap(frames[frameIndex], null, destination, new Paint());
}
private void scaleRect(Rect rect)
{
float whRatio = (float)(frames[frameIndex].getWidth() / frames[frameIndex].getHeight());
if (rect.width() > rect.height())
{
rect.left = rect.right - (int)(rect.height() * whRatio);
}
else
{
rect.top = rect.bottom - (int)(rect.width() * (1 / whRatio));
}
}
public void update()
{
if (!isPlaying)
return;
if (System.currentTimeMillis() - lastFrame > frameTime * 1000)
{
frameIndex++;
if (frameIndex >= frames.length)
frameIndex = 0;
lastFrame = System.currentTimeMillis();
}
}
}
i dont think you necessarily needed all that but just in case :). thanks for any comments to improve or help.
OutOfMemoryError basically means that you tried to use more memory than you can. In this specific example you (bitmap) tried to allocate 360KB though you could only allocate 78KB more. You might have a memory leak somewhere or your bitmap might be too big. I think your Bitmaps might be leaking memory. I'm not an Android expert though.
I'd recommend you to create a method in Obstacle like recycle or something along this way. Then every time you remove Obstacle from obstacles in ObstacleManager call that method. In that method you should aim to recycle all no longer used bitmaps. I'd do it by calling either Animation#recycle on every of your animations or calling AnimationManagerObstacle#recycle. (Animation#recycle would be meant to call recycle on every one of your frames.)
I'm trying to add multiple sprites to android game using an Array but at the minute only one will display and when I click it rather than it changing to the new sprite animation it freezes on the screen here is the code within my GameView.java and Sprite.java.
GameView.java:
/**
* This class takes care of surface for drawing and touches
*
*/
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
/* Member (state) fields */
private GameLoopThread gameLoopThread;
private Paint paint; // Reference a paint object
/** The drawable to use as the background of the animation canvas */
private Bitmap mBackgroundImage;
private Sprite sprite;
private ArrayList<Sprite> spritesArrayList;
int SpriteAmount = 3;
private int hitCount;
private boolean GameOver = false;
/* For the countdown timer */
private long startTime; // Timer to count down from
private final long interval = 1 * 1000; // 1 sec interval
private CountDownTimer countDownTimer; // Reference to class
private boolean timerRunning = false;
private String displayTime; // To display time on the screen
public GameView(Context context) {
super(context);
spritesArrayList = new ArrayList<Sprite>();
// Focus must be on GameView so that events can be handled.
this.setFocusable(true);
// For intercepting events on the surface.
this.getHolder().addCallback(this);
mBackgroundImage = BitmapFactory.decodeResource(this.getResources(),
R.drawable.dbz);
}
/* Called immediately after the surface created */
public void surfaceCreated(SurfaceHolder holder) {
mBackgroundImage = Bitmap.createScaledBitmap(mBackgroundImage,
getWidth(), getHeight(), true);
// We can now safely setup the game start the game loop.
ResetGame();// Set up a new game up - could be called by a 'play again
// option'
gameLoopThread = new GameLoopThread(this.getHolder(), this);
gameLoopThread.running = true;
gameLoopThread.start();
}
// Sprite List
// To initialise/reset game
private void ResetGame() {
//sprite = new Sprite(this);
for (int P = 0; P < SpriteAmount; P++) {
spritesArrayList.add(sprite = new Sprite(this));
}
hitCount = 0;
GameOver = false;
/* Set paint details */
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
// Set timer
startTime = 10;// Start at 10s to count down
// Create new object - convert startTime to milliseconds
countDownTimer = new MyCountDownTimer(startTime * 1000, interval);
countDownTimer.start();// Start it running
timerRunning = true;
}
// This class updates and manages the assets prior to drawing - called from
// the Thread
public void update() {
for (int P = 0; P < SpriteAmount; P++) {
GameOver = false;
spritesArrayList.get(P).update();
}
}
/**
* To draw the game to the screen This is called from Thread, so
* synchronisation can be done
*/
public void doDraw(Canvas canvas) {
canvas.drawBitmap(mBackgroundImage, 0, 0, null);
if (GameOver == false) {
sprite.draw(canvas);
} else if (GameOver == true) {
}
// Draw all the objects on the canvas
canvas.drawText("Hits Obtained =" + hitCount, 5, 25, paint);
canvas.drawText("Time Remaining =" + displayTime, 5, 40, paint);
if (GameOver == true) {
canvas.drawText("Return To Main Menu using return button", 5, 60,
paint);
}
}
// To be used if we need to find where screen was touched
public boolean onTouchEvent(MotionEvent event) {
for (int P = 0; P < SpriteAmount; P++) {
if (spritesArrayList.get(P).wasItTouched(event.getX(), event.getY())) {
/* For now, just renew the Sprite */
spritesArrayList.add(sprite = new Sprite(this));
hitCount++;
}
}
return true;
}
public void surfaceDestroyed(SurfaceHolder holder) {
gameLoopThread.running = false;
// Shut down the game loop thread cleanly.
boolean retry = true;
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
/* Countdown Timer - private class */
private class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
public void onFinish() {
displayTime = "Times Over!";
timerRunning = false;
countDownTimer.cancel();
GameOver = true;
}
public void onTick(long millisUntilFinished) {
displayTime = " " + millisUntilFinished / 1000;
}
}// End of MyCountDownTimer
public int getHitCount() {
// TODO Auto-generated method stub
return hitCount;
}
}
Sprite.java:
public class Sprite {
// Needed for new random coordinates.
private Random random = new Random();
// x,y position of sprite - initial position (0,50)
int x = random.nextInt(500);
int X = random.nextInt(500);
int y = random.nextInt(1000);
int Y = random.nextInt(1000);
private int xSpeed = 10;// Horizontal increment of position (speed)
// apply at later date random.nextInt(10)
private int ySpeed = 10;// Vertical increment of position (speed)
// apply at later date random.nextInt(10)
private GameView gameView;
private Bitmap spritebmp;
// Width and Height of the Sprite image
private int bmp_width;
private int bmp_height;
private Integer[] imgid = { R.drawable.kidbuu, R.drawable.guko,
R.drawable.guko_ssj1
};
// Calculation for reverse direction
// x = x - (x - x)
// y = y - (y - y)
public Sprite(GameView gameView) {
this.gameView = gameView;
spritebmp = BitmapFactory.decodeResource(gameView.getResources(),
R.drawable.guko);
this.bmp_width = spritebmp.getWidth();
this.bmp_height = spritebmp.getHeight();
}
// update the position of the sprite
public void update() {
x = x + xSpeed;
y = y + ySpeed;
wrapAround(); // Adjust motion of sprite.
}
public void ReverseRandom() {
X = (x - (x - x));
Y = (y - (y - y));
}
public void draw(Canvas canvas) {
// Draw sprite image
// y = random.nextInt(500);
// x = random.nextInt(500);
canvas.drawBitmap(spritebmp, x, y, null);
}
public int calcX(int value) {
return random.nextInt(value);
}
public int calcY(int value) {
return random.nextInt(value);
}
public void wrapAround() {
ReverseRandom();
// Code to wrap around
if (x < 0)
x = X; // increment x whilst not off screen
if (x >= gameView.getWidth() - spritebmp.getWidth() - xSpeed) { // if
// gone
// of
// the
// right
// sides
// of
// screen
xSpeed = -5;
}
if (x + xSpeed <= 0) {
xSpeed = 5;
}
x = x + xSpeed;
if (y < 0)
y = Y;// increment y whilst not off screen
if (y >= gameView.getHeight() - spritebmp.getWidth() - ySpeed) {// if
// gone
// of
// the
// bottom
// of
// screen
ySpeed = -5;
}
if (y + ySpeed <= 0) {
ySpeed = 5;
}
y = y + ySpeed;
}
/* Checks if the Sprite was touched. */
public boolean wasItTouched(float ex, float ey) {
boolean touched = false;
if ((x <= ex) && (ex < x + bmp_width) && (y <= ey)
&& (ey < y + bmp_height)) {
touched = true;
}
return touched;
}// End of wasItTouched
public void change(Integer[] P) {
imgid = P;
spritebmp = BitmapFactory.decodeResource(gameView.getResources(),
R.drawable.guko_ssj1);
}
}