So I've returned to the streetfighter libgdx clone And Ive managed to draw ken's animations. But, I realised once removing the background that two kens were being drawn one behind the other that you can only see when you jump (after removing background) this other ken sprite doesnt jump. but can move horizontally.
My question is, is it where I'm defining Ken or how have i managed to draw him twice?
I'm baffled...
ken class
public class Ken extends Player {
private static final int FRAME_COLS = 6, FRAME_ROWS = 1;
private static final int COLUMNS_KICK = 6;
private static final int COLUMNS_LEFT = 8;
private static final int COLUMNS_RIGHT = 8;
private static final int COLUMNS_JUMP = 10;
private static final int COLUMNS_PUNCH = 6;
private static final int COLUMNS_FRONTFLIP = 8;
private static final int COLUMNS_BACKFLIP = 8;
private static final int COLUMNS_CROUCH_PUNCH= 3;
private static final int COLUMNS_UPPERCUT = 9;
public static final int FRAME_FRONTFLIP = 1;
public static final int FRAME_BACKLIP = 1;
public enum State {
IDLE, LEFT, RIGHT, JUMP, DUCK, PUNCH, HIT, KICK, END, BLOCK
}
Animation<TextureRegion> walkAnimation;
Animation<TextureRegion> kickAnimation;
Animation<TextureRegion> punchAnimation;
Animation<TextureRegion> leftAnimation;
Animation<TextureRegion> rightAnimation;
Animation<TextureRegion> jumpAnimation;
Animation<TextureRegion> frontFlipAnimation;
Animation<TextureRegion> backFlipAnimation;
Animation<TextureRegion> crouchPunchAnimation;
Animation<TextureRegion> uppercutAnimation;
Texture walkSheet;
Texture kickSheet;
Texture punchSheet;
Texture leftSheet;
Texture rightSheet;
Texture jumpSheet;
Texture frontFlipSheet;
Texture backFlipSheet;
Texture crouchPunchSheet;
Texture uppercutSheet;
public Body body;
public World world;
boolean alive = true;
private final static int STARTING_X = 50;
private final static int STARTING_Y = 30;
TextureRegion reg;
float stateTime;
public Ken(GameScreen screen){
this.world = screen.getWorld();
defineKen();
createIdleAnimation();
kickAnimation();
punchAnimation();
lefttAnimation();
righttAnimation();
jumpAnimation();
uppercutAnimation();
crouchPunchAnimation();
frontFlipAnimation();
backFlipAnimation();
this.setPosition(STARTING_X, STARTING_Y);
}
public void createIdleAnimation() {
walkSheet = new Texture(Gdx.files.internal("ken/idle.png"));
TextureRegion[][] tmp = TextureRegion.split(walkSheet,
walkSheet.getWidth() / FRAME_COLS,
walkSheet.getHeight() / FRAME_ROWS);
TextureRegion[] 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<TextureRegion>(0.1f, walkFrames);
stateTime = 0f;
reg=walkAnimation.getKeyFrame(0);
}
public void kickAnimation(){
kickSheet = new Texture(Gdx.files.internal("ken/kick_low.png"));
TextureRegion [][] tmp = TextureRegion.split(kickSheet, kickSheet.getWidth() / COLUMNS_KICK,
kickSheet.getHeight() / FRAME_ROWS);
TextureRegion[] kickFrames = new TextureRegion[COLUMNS_KICK * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < FRAME_COLS; j++) {
kickFrames[index++] = tmp[i][j];
}
}
kickAnimation = new Animation<TextureRegion>(8f, kickFrames);
stateTime = 6f;
reg = kickAnimation.getKeyFrame(1);
}
public void lefttAnimation(){
leftSheet = new Texture(Gdx.files.internal("ken/parry_b.png"));
TextureRegion [][] tmp = TextureRegion.split(leftSheet, leftSheet.getWidth() / COLUMNS_LEFT,
leftSheet.getHeight() / FRAME_ROWS);
TextureRegion[] leftFrames = new TextureRegion[COLUMNS_LEFT * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < COLUMNS_LEFT; j++) {
leftFrames[index++] = tmp[i][j];
}
}
leftAnimation = new Animation<TextureRegion>(0.1f, leftFrames);
stateTime = 0f;
reg = punchAnimation.getKeyFrame(0);
}
public void righttAnimation(){
rightSheet = new Texture(Gdx.files.internal("ken/parry_f.png"));
TextureRegion [][] tmp = TextureRegion.split(rightSheet, rightSheet.getWidth() / COLUMNS_RIGHT,
rightSheet.getHeight() / FRAME_ROWS);
TextureRegion[] rightFrames = new TextureRegion[COLUMNS_RIGHT * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < COLUMNS_RIGHT; j++) {
rightFrames[index++] = tmp[i][j];
}
}
rightAnimation = new Animation<TextureRegion>(0.1f, rightFrames);
stateTime = 0f;
reg = rightAnimation.getKeyFrame(0);
}
public void punchAnimation(){
punchSheet = new Texture(Gdx.files.internal("ken/punch.png"));
TextureRegion [][] tmp = TextureRegion.split(punchSheet, punchSheet.getWidth() / COLUMNS_PUNCH,
punchSheet.getHeight() / FRAME_ROWS);
TextureRegion[] punchFrames = new TextureRegion[COLUMNS_PUNCH * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < COLUMNS_PUNCH; j++) {
punchFrames[index++] = tmp[i][j];
}
}
punchAnimation = new Animation<TextureRegion>(1f, punchFrames);
stateTime = 0f;
reg = punchAnimation.getKeyFrame(0);
}
public void jumpAnimation(){
jumpSheet = new Texture(Gdx.files.internal("ken/jump.png"));
TextureRegion [][] tmp = TextureRegion.split(jumpSheet, jumpSheet.getWidth() / COLUMNS_JUMP,
jumpSheet.getHeight() / FRAME_ROWS);
TextureRegion[] jumpFrames = new TextureRegion[COLUMNS_JUMP * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < COLUMNS_JUMP; j++) {
jumpFrames[index++] = tmp[i][j];
}
}
jumpAnimation = new Animation<TextureRegion>(0.1f, jumpFrames);
stateTime = 0f;
reg = jumpAnimation.getKeyFrame(0);
}
public void frontFlipAnimation(){
frontFlipSheet = new Texture(Gdx.files.internal("ken/front_flip.png"));
TextureRegion [][] tmp = TextureRegion.split(frontFlipSheet, frontFlipSheet.getWidth() / COLUMNS_FRONTFLIP,
frontFlipSheet.getHeight() / FRAME_ROWS);
TextureRegion[] frontFlipFrames = new TextureRegion[COLUMNS_FRONTFLIP * FRAME_FRONTFLIP];
int index = 0;
for (int i = 0; i < FRAME_FRONTFLIP; i++) {
for (int j = 0; j < COLUMNS_FRONTFLIP; j++) {
frontFlipFrames[index++] = tmp[i][j];
}
}
frontFlipAnimation = new Animation<TextureRegion>(0.1f, frontFlipFrames);
stateTime = 0f;
reg = frontFlipAnimation.getKeyFrame(0);
}
public void backFlipAnimation(){
backFlipSheet = new Texture(Gdx.files.internal("ken/back_flip.png"));
TextureRegion [][] tmp = TextureRegion.split(backFlipSheet, backFlipSheet.getWidth() / COLUMNS_BACKFLIP,
backFlipSheet.getHeight() / FRAME_BACKLIP);
TextureRegion[] backFlipFrames = new TextureRegion[COLUMNS_BACKFLIP * FRAME_BACKLIP];
int index = 0;
for (int i = 0; i < FRAME_BACKLIP; i++) {
for (int j = 0; j < COLUMNS_BACKFLIP; j++) {
backFlipFrames[index++] = tmp[i][j];
}
}
backFlipAnimation = new Animation<TextureRegion>(0.1f, backFlipFrames);
stateTime = 0f;
reg = backFlipAnimation.getKeyFrame(0);
}
public void crouchPunchAnimation(){
crouchPunchSheet = new Texture(Gdx.files.internal("ken/crouch_punch.png"));
TextureRegion [][] tmp = TextureRegion.split(crouchPunchSheet, crouchPunchSheet.getWidth() / COLUMNS_CROUCH_PUNCH,
crouchPunchSheet.getHeight() / FRAME_ROWS);
TextureRegion[] crouchPunchFrames = new TextureRegion[COLUMNS_CROUCH_PUNCH * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < COLUMNS_CROUCH_PUNCH; j++) {
crouchPunchFrames[index++] = tmp[i][j];
}
}
crouchPunchAnimation = new Animation<TextureRegion>(0.1f, crouchPunchFrames);
stateTime = 1f;
reg = crouchPunchAnimation.getKeyFrame(5);
}
public void uppercutAnimation(){
uppercutSheet = new Texture(Gdx.files.internal("ken/uppercut.png"));
TextureRegion [][] tmp = TextureRegion.split(uppercutSheet, uppercutSheet.getWidth() / COLUMNS_UPPERCUT,
uppercutSheet.getHeight() / FRAME_ROWS);
TextureRegion[] uppercutFrames = new TextureRegion[COLUMNS_UPPERCUT * FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++) {
for (int j = 0; j < COLUMNS_UPPERCUT; j++) {
uppercutFrames[index++] = tmp[i][j];
}
}
uppercutAnimation = new Animation<TextureRegion>(0.1f, uppercutFrames);
stateTime = 0f;
reg = uppercutAnimation.getKeyFrame(0);
}
#Override
public void act(float delta) {
super.act(delta);
stateTime += delta;
// setX(body.getPosition().x);
setY(body.getPosition().y);
stateTime += delta;
reg = walkAnimation.getKeyFrame(stateTime,true);
if(Gdx.input.isKeyPressed(Input.Keys.A)){
reg = kickAnimation.getKeyFrame(stateTime, false);
this.addAction(Actions.moveTo(getX() +5, getY(), 1F));
}
if(Gdx.input.isKeyPressed(Input.Keys.S)){
reg = punchAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 2, getY(), 1F));
}
if(Gdx.input.isKeyPressed(Input.Keys.LEFT)){
reg = leftAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() - 10, getY(), 1 / 10f ));
}
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)){
reg = rightAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 10, getY(), 1 /10f));
}
if(Gdx.input.isKeyPressed(Input.Keys.UP)){
reg = jumpAnimation.getKeyFrame(stateTime, false);
body.applyLinearImpulse(new Vector2(0, 10), body.getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.D)){
reg = frontFlipAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 5, getY(), 1 / 10f));
}
if(Gdx.input.isKeyPressed(Input.Keys.W)){
reg = backFlipAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() - 5, getY(), 1 / 10F));
}
if(Gdx.input.isKeyPressed(Input.Keys.DOWN)&& Gdx.input.isKeyPressed(Input.Keys.S)){
reg = crouchPunchAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 2, getY(), 1f));
}
if(Gdx.input.isKeyPressed(Input.Keys.SPACE)){
reg = uppercutAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 5, getY(), 1 / 10F));
}
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(reg,getX(),getY(),getWidth()/2,getHeight()/2,getWidth(),getHeight(),getScaleX(),getScaleY(),getRotation());
}
private void defineKen(){
BodyDef bdef = new BodyDef();
bdef.position.set(20F, 6.5F);
bdef.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(bdef);
BodyDef groundBodyDef = new BodyDef();
groundBodyDef.position.set(20, 0f);
Body groundBody = world.createBody(groundBodyDef);
PolygonShape groundBox = new PolygonShape();
groundBox.setAsBox(70, 1.0f);
groundBody.createFixture(groundBox, 0.0f);
groundBox.dispose();
PolygonShape shape = new PolygonShape();
shape.setAsBox(76 / 2 / 10f, 136 / 2 / 10f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0f;
body.createFixture(fixtureDef);
shape.dispose();
}
}
Game class
public class GameScreen extends AbstractScreen {
Ken ken;
private Texture background;
private Image backgroundImg;
private World world;
public GameScreen(BeatDemGame game) {
super(game);
init();
}
#Override
protected void init() {
world = new World(new Vector2(0, -40f), true);
initBackground();
}
private void initBackground() {
// background = new Texture("city_stage.gif");
// backgroundImg = new Image(background);
// backgroundImg.setPosition(0, 0);
// stage.addActor(backgroundImg);
initPlayer();
}
private void initPlayer() {
ken = new Ken(this);
ken.setSize(70,90);
ken.setDebug(true);
stage.addActor(ken);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
super.render(delta);
update();
stage.draw();
}
private void update() {
stage.act();
world.step(1 / 30f, 6, 2);
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
game.dispose();
}
public World getWorld() {
return world;
}
}
I don't want this effect obviously as I only need 1 ken. i don't understand why its being drawn twice eg. where in the code is this being executed ?If i put a background the ken that doesn't jump sits behind the background and you can't see it....
thanks
updated code
public class Ken extends Actor {
.....
#Override
public void act(float delta) {
super.act(delta);
// stateTime += delta;
// setX(body.getPosition().x);
setY(body.getPosition().y);
stateTime += delta;
reg = walkAnimation.getKeyFrame(stateTime,true);
if(Gdx.input.isKeyPressed(Input.Keys.A)){
reg = kickAnimation.getKeyFrame(stateTime, false);
this.addAction(Actions.moveTo(getX() +5, getY(), 1F));
}
if(Gdx.input.isKeyPressed(Input.Keys.S)){
reg = punchAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 2, getY(), 1F));
}
if(Gdx.input.isKeyPressed(Input.Keys.LEFT)){
reg = leftAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() - 10, getY(), 1 / 10f ));
}
if(Gdx.input.isKeyPressed(Input.Keys.RIGHT)){
reg = rightAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 10, getY(), 1 /10f));
}
if(Gdx.input.isKeyPressed(Input.Keys.UP)){
reg = jumpAnimation.getKeyFrame(stateTime, false);
body.applyLinearImpulse(new Vector2(0, 10), body.getWorldCenter(), true);
}
if(Gdx.input.isKeyPressed(Input.Keys.D)){
reg = frontFlipAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 5, getY(), 1 / 10f));
}
if(Gdx.input.isKeyPressed(Input.Keys.W)){
reg = backFlipAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() - 5, getY(), 1 / 10F));
}
if(Gdx.input.isKeyPressed(Input.Keys.DOWN)&& Gdx.input.isKeyPressed(Input.Keys.S)){
reg = crouchPunchAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 2, getY(), 1f));
}
if(Gdx.input.isKeyPressed(Input.Keys.SPACE)){
reg = uppercutAnimation.getKeyFrame(stateTime, true);
this.addAction(Actions.moveTo(getX() + 5, getY(), 1 / 10F));
}
}
#Override
public void draw(Batch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(reg,getX(),getY(),getWidth()/2,getHeight()/2,getWidth(),getHeight(),getScaleX(),getScaleY(),getRotation());
}
private void defineKen(){
BodyDef bdef = new BodyDef();
bdef.position.set(20F, 6.5F);
bdef.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(bdef);
BodyDef groundBodyDef = new BodyDef();
groundBodyDef.position.set(20, 0f);
Body groundBody = world.createBody(groundBodyDef);
PolygonShape groundBox = new PolygonShape();
groundBox.setAsBox(70, 1.0f);
groundBody.createFixture(groundBox, 0.0f);
groundBox.dispose();
PolygonShape shape = new PolygonShape();
shape.setAsBox(76 / 2 / 10f, 136 / 2 / 10f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0f;
body.createFixture(fixtureDef);
shape.dispose();
}
}
I still get two of ken.
In your Ken class, you override the draw() method to draw Ken on your own but you also call super.draw() which also draws Ken.
Change:
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(reg,getX(),getY(),getWidth()/2,getHeight()/2,getWidth(),getHeight(),getScaleX(),getScaleY(),getRotation());
}
to:
#Override
public void draw(Batch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
batch.draw(reg,getX(),getY(),getWidth()/2,getHeight()/2,getWidth(),getHeight(),getScaleX(),getScaleY(),getRotation());
}
because super.draw() already draw Ken and three lines later you draw Ken a second time with batch.draw()
How does your Player class look like? I currently see only one line where you are actually drawing a texture region to screen.
batch.draw(reg,getX(),getY(),getWidth()/2,getHeight()/2,getWidth(),getHeight(),getScaleX(),getScaleY(),getRotation());
And my guess is, since you want to draw every "Player" to the screen you are drawing it there too. Because you are also calling the draw method of the player by having super.draw(batch, parentAlpha); it will be drawing both.
Related
I've looked at several examples of people creating tile maps, and I am unable to get the tile position where my mouse is pointed at.
I am using a spritebatch and GameTile[][] to create the map. Keep in mind that the tiles themselves are isometric and not actually a square.
The method renderMap() is where the map is actually is being rendered. createMap() just sets the initial GameTiles for an empty map.
The map is able to be dragged and zoomed in and out using Ortho camera.
Zooming out gives me an issue as well, the tiles seem to be shifted over on click
public class MapEditor implements GameScene {
private GameContext context;
private SpriteBatch batch;
private OrthographicCamera camera;
public static GameTile[][] tiles; //GameTile.WIDTH = 64 & GameTile.HEIGHT =48
public static final int MAP_WIDTH = 20;
public static final int MAP_HEIGHT = 36;
public MapEditor(GameContext context) {
this.context = context;
tiles = new GameTile[MAP_WIDTH][MAP_HEIGHT];
}
#Override
public void create() {
renderer = new ShapeRenderer();
this.batch = new SpriteBatch();
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
public void createMap() {
// Create the sea tiles
for (int x = 0; x < MAP_WIDTH; x++) {
for (int y = 0; y < MAP_HEIGHT; y++) {
if (y < 3 || y > 32) {
if(tiles[x][y] == null) {
tiles[x][y] = safezone;
}
}
else {
if(tiles[x][y] == null) {
tiles[x][y] = cell;
}
}
}
}
}
#Override
public void update(){
// update the camera
camera.update();
}
#Override
public void render() {
batch.setProjectionMatrix(camera.combined);
batch.begin();
Gdx.gl.glViewport(0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
renderMap();
batch.end();
}
public int getTileX(float x, float y) {
/*
* getRegionWidth() = TILE_WIDTH_HALF
* getRegionHeight() = TILE_HEIGHT_HALF
* these are the ones being added to worldCoords.x/y
*/
Vector3 worldCoords = camera.unproject(new Vector3(x, y, 0));
return (int)((TILE_WIDTH_HALF * ((-TILE_HEIGHT_HALF + (worldCoords.y + TILE_HEIGHT_HALF)) /
TILE_HEIGHT_HALF) + (worldCoords.x + TILE_WIDTH_HALF)) / TILE_WIDTH_HALF) / 2;
}
public int getTileY(float x, float y) {
/*
* getRegionWidth() = TILE_WIDTH_HALF
* getRegionHeight() = TILE_HEIGHT_HALF
* these are the ones being added to worldCoords.x/y
*/
Vector3 worldCoords = camera.unproject(new Vector3(x, y, 0));
return (int)(((-TILE_HEIGHT_HALF * (TILE_WIDTH_HALF + (worldCoords.x + TILE_WIDTH_HALF)) /
TILE_WIDTH_HALF) + (worldCoords.y + TILE_HEIGHT_HALF)) / TILE_HEIGHT_HALF) / 2;
}
#Override
public boolean handleClick(float x, float y, int button) {
int tileX = getTileX(x,y);
int tileY = getTileY(x,y);
System.out.println("Tile:"+tileX + ","+tileY);
}
private void renderMap() {
for (int i = 0; i < tiles.length; i++) {
for(int j = 0; j < tiles[i].length; j++) {
TextureRegion region = tiles[i][j].getRegion();
int x = (i * GameTile.TILE_WIDTH / 2) - (j * GameTile.TILE_WIDTH / 2) - region.getRegionWidth() / 2;
int y = (i * GameTile.TILE_HEIGHT / 2) + (j * GameTile.TILE_HEIGHT / 2) - region.getRegionHeight() / 2;
if (canDraw(x, y, GameTile.TILE_WIDTH, GameTile.TILE_HEIGHT)) {
batch.draw(region, x, y);
}
}
}
}
Actual tile before doing anything to it;
Actual:
Desired:
Converting Cartesian coordinates to isometric is (sort of) done like this:
float isometricX = cartesianX - cartesianY;
float isometricY = (cartesianX + cartesianY) * 0.5f;
The formula needs to be scaled by the height-to-width ratio of the tiles as well and I think that is where it's going wrong in your code.
Given an unprojected worldMousePosition you can get the coordinates and tile coordinates like this:
float r = (float) TILE_HEIGHT / (float) TILE_WIDTH;
float mapx = (worldMousePosition.x / TILE_HEIGHT + worldMousePosition.y / (TILE_HEIGHT * r)) * r;
float mapy = (worldMousePosition.y / (TILE_HEIGHT * r) - (worldMousePosition.x / TILE_HEIGHT)) * r;
worldPosition = new Vector2(mapx - 0.5f, mapy + 0.5f); // -.5/+.5 because the drawing isn't aligned to the tile, it's aligned to the image
int tileX = (int) worldPosition.x;
int tileY = (int) worldPosition.y;
Full source code for the example above:
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
public class SandboxGame extends Game {
public static final int TILE_NONE = -1;
public static final int MAP_WIDTH = 20;
public static final int MAP_HEIGHT = 36;
public static final int TILE_WIDTH = 64;
public static final int TILE_HEIGHT = 48;
private SpriteBatch batch;
private OrthographicCamera camera;
private BitmapFont font;
private Vector3 unprojectVector = new Vector3();
private Vector2 worldMousePosition = new Vector2();
private Vector2 worldPosition = new Vector2();
private Texture[] textures;
private int[][] tiles = new int[MAP_WIDTH][MAP_HEIGHT];
#Override
public void create() {
batch = new SpriteBatch();
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
font = new BitmapFont(Gdx.files.internal("default.fnt"), Gdx.files.internal("default.png"), false);
textures = new Texture[] {
new Texture(Gdx.files.internal("tile.png"))
};
for(int x = 0; x < MAP_WIDTH; ++x) {
for(int y = 0; y < MAP_HEIGHT; ++y) {
int rnd = MathUtils.random(10);
if (rnd < 1)
tiles[x][y] = TILE_NONE;
else
tiles[x][y] = 0;
}
}
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
float scrollSpeed = 64;
float zoomSpeed = 2;
float delta = Gdx.graphics.getDeltaTime();
if (Gdx.input.isKeyPressed(Input.Keys.A))
camera.position.x -= delta * scrollSpeed;
if (Gdx.input.isKeyPressed(Input.Keys.D))
camera.position.x += delta * scrollSpeed;
if (Gdx.input.isKeyPressed(Input.Keys.W))
camera.position.y += delta * scrollSpeed;
if (Gdx.input.isKeyPressed(Input.Keys.S))
camera.position.y -= delta * scrollSpeed;
if (Gdx.input.isKeyPressed(Input.Keys.Q))
camera.zoom = Math.min(camera.zoom + zoomSpeed * delta, 8.0f);
if (Gdx.input.isKeyPressed(Input.Keys.E))
camera.zoom = Math.max(camera.zoom - zoomSpeed * delta, 0.5f);
camera.update();
int mx = Gdx.input.getX();
int my = Gdx.input.getY();
camera.unproject(unprojectVector.set(mx, my, 0.0f));
worldMousePosition.set(unprojectVector.x, unprojectVector.y);
float r = (float) TILE_HEIGHT / (float) TILE_WIDTH;
float mapx = (worldMousePosition.x / TILE_HEIGHT + worldMousePosition.y / (TILE_HEIGHT * r)) * r;
float mapy = (worldMousePosition.y / (TILE_HEIGHT * r) - (worldMousePosition.x / TILE_HEIGHT)) * r;
worldPosition = new Vector2(mapx - 0.5f, mapy + 0.5f); // -.5/+.5 because the drawing isn't aligned to the tile, it's aligned to the image
int tileX = (int) worldPosition.x;
int tileY = (int) worldPosition.y;
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (int col = MAP_WIDTH - 1; col >= 0; --col) {
for (int row = MAP_HEIGHT - 1; row >= 0; --row) {
if (tiles[col][row] != TILE_NONE) {
Texture texture = textures[tiles[col][row]];
int x = (col * TILE_WIDTH / 2) - (row * TILE_WIDTH / 2);
int y = (col * TILE_HEIGHT / 2) + (row * TILE_HEIGHT / 2);
batch.setColor(col == tileX && row == tileY ? Color.GRAY : Color.WHITE);
batch.draw(texture, x, y);
}
}
}
if (Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
for (int col = MAP_WIDTH - 1; col >= 0; --col) {
for (int row = MAP_HEIGHT - 1; row >= 0; --row) {
int x = (col * TILE_WIDTH / 2) - (row * TILE_WIDTH / 2);
int y = (col * TILE_HEIGHT / 2) + (row * TILE_HEIGHT / 2);
font.draw(batch, String.format("(%d, %d)", col, row), x, y);
}
}
}
String str = String.format("World position (%.2f, %.2f), Tile (%d, %d)", worldPosition.x, worldPosition.y, (int)worldPosition.x, (int)worldPosition.y);
font.draw(batch, str, worldMousePosition.x, worldMousePosition.y);
batch.end();
}
}
I cant respond to bornander's post, but my tweak would be at
int tileX = (int) Math.Floor(worldPosition.x);
int tileY = (int) Math.Floor(worldPosition.y);
Where simple (int) cast will provide wrong position around 0 with negative values, if there are tiles, while using Math.Floor will work as intended.
My view matrix in my camera class is setup up correctly, with the rotation and negative translation, but it moves the camera somewhere else, and I can't seem to find my model. Rotation and translation matrices are working because translations are working and my model and projection matrices are also working, but when I add the view matrix, it only shows parts of the model. By the way, made my own matrix math classes.
Matrix Math Class
package engine.maths;
public class Matrix4f {
private float[][] matrix;
public Matrix4f() {
matrix = new float[4][4];
}
public Matrix4f identity() {
matrix[0][0] = 1; matrix[0][1] = 0; matrix[0][2] = 0; matrix[0][3] = 0;
matrix[1][0] = 0; matrix[1][1] = 1; matrix[1][2] = 0; matrix[1][3] = 0;
matrix[2][0] = 0; matrix[2][1] = 0; matrix[2][2] = 1; matrix[2][3] = 0;
matrix[3][0] = 0; matrix[3][1] = 0; matrix[3][2] = 0; matrix[3][3] = 1;
return this;
}
public Matrix4f translate(Vector3f vector) {
matrix[0][0] = 1; matrix[0][1] = 0; matrix[0][2] = 0; matrix[0][3] = vector.getX();
matrix[1][0] = 0; matrix[1][1] = 1; matrix[1][2] = 0; matrix[1][3] = vector.getY();
matrix[2][0] = 0; matrix[2][1] = 0; matrix[2][2] = 1; matrix[2][3] = vector.getZ();
matrix[3][0] = 0; matrix[3][1] = 0; matrix[3][2] = 0; matrix[3][3] = 1;
return this;
}
public Matrix4f rotate(Vector3f vector) {
Matrix4f rotateX = new Matrix4f();
Matrix4f rotateY = new Matrix4f();
Matrix4f rotateZ = new Matrix4f();
Vector3f rotatedVector = new Vector3f((float) Math.toRadians(vector.getX()), (float) Math.toRadians(vector.getY()), (float) Math.toRadians(vector.getZ()));
rotateZ.matrix[0][0] = (float)Math.cos(rotatedVector.getZ()); rotateZ.matrix[0][1] = -(float)Math.sin(rotatedVector.getZ()); rotateZ.matrix[0][2] = 0; rotateZ.matrix[0][3] = 0;
rotateZ.matrix[1][0] = (float)Math.sin(rotatedVector.getZ()); rotateZ.matrix[1][1] = (float)Math.cos(rotatedVector.getZ()); rotateZ.matrix[1][2] = 0; rotateZ.matrix[1][3] = 0;
rotateZ.matrix[2][0] = 0; rotateZ.matrix[2][1] = 0; rotateZ.matrix[2][2] = 1; rotateZ.matrix[2][3] = 0;
rotateZ.matrix[3][0] = 0; rotateZ.matrix[3][1] = 0; rotateZ.matrix[3][2] = 0; rotateZ.matrix[3][3] = 1;
rotateX.matrix[0][0] = 1; rotateX.matrix[0][1] = 0; rotateX.matrix[0][2] = 0; rotateX.matrix[0][3] = 0;
rotateX.matrix[1][0] = 0; rotateX.matrix[1][1] = (float)Math.cos(rotatedVector.getX()); rotateX.matrix[1][2] = -(float)Math.sin(rotatedVector.getX()); rotateX.matrix[1][3] = 0;
rotateX.matrix[2][0] = 0; rotateX.matrix[2][1] = (float)Math.sin(rotatedVector.getX()); rotateX.matrix[2][2] = (float)Math.cos(rotatedVector.getX()); rotateX.matrix[2][3] = 0;
rotateX.matrix[3][0] = 0; rotateX.matrix[3][1] = 0; rotateX.matrix[3][2] = 0; rotateX.matrix[3][3] = 1;
rotateY.matrix[0][0] = (float)Math.cos(rotatedVector.getY()); rotateY.matrix[0][1] = 0; rotateY.matrix[0][2] = -(float)Math.sin(rotatedVector.getY()); rotateY.matrix[0][3] = 0;
rotateY.matrix[1][0] = 0; rotateY.matrix[1][1] = 1; rotateY.matrix[1][2] = 0; rotateY.matrix[1][3] = 0;
rotateY.matrix[2][0] = (float)Math.sin(rotatedVector.getY()); rotateY.matrix[2][1] = 0; rotateY.matrix[2][2] = (float)Math.cos(rotatedVector.getY()); rotateY.matrix[2][3] = 0;
rotateY.matrix[3][0] = 0; rotateY.matrix[3][1] = 0; rotateY.matrix[3][2] = 0; rotateY.matrix[3][3] = 1;
matrix = rotateZ.mul(rotateY.mul(rotateX)).getMatrix();
return this;
}
public Matrix4f scale(Vector3f vector) {
matrix[0][0] = vector.getX(); matrix[0][1] = 0; matrix[0][2] = 0; matrix[0][3] = 0;
matrix[1][0] = 0; matrix[1][1] = vector.getY(); matrix[1][2] = 0; matrix[1][3] = 0;
matrix[2][0] = 0; matrix[2][1] = 0; matrix[2][2] = vector.getZ(); matrix[2][3] = 0;
matrix[3][0] = 0; matrix[3][1] = 0; matrix[3][2] = 0; matrix[3][3] = 1;
return this;
}
public Matrix4f projection(float fov, float aspectRatio, float zNear, float zFar) {
float tanHalfFOV = (float) Math.tan(Math.toRadians(fov / 2));
float zRange = zNear - zFar;
matrix[0][0] = 1.0f / (tanHalfFOV * aspectRatio); matrix[0][1] = 0; matrix[0][2] = 0; matrix[0][3] = 0;
matrix[1][0] = 0; matrix[1][1] = 1.0f / tanHalfFOV; matrix[1][2] = 0; matrix[1][3] = 0;
matrix[2][0] = 0; matrix[2][1] = 0; matrix[2][2] = (-zNear - zFar) / zRange; matrix[2][3] = 2 * zFar * zNear / zRange;
matrix[3][0] = 0; matrix[3][1] = 0; matrix[3][2] = 1; matrix[3][3] = 0;
return this;
}
public Matrix4f mul(Matrix4f m) {
Matrix4f result = new Matrix4f();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
result.set(i, j, matrix[i][0] * m.get(0, j) +
matrix[i][1] * m.get(1, j) +
matrix[i][2] * m.get(2, j) +
matrix[i][3] * m.get(3, j));
}
}
return result;
}
public float[][] getMatrix() {
return matrix;
}
public void setMatrix(float[][] matrix) {
this.matrix = matrix;
}
public float get(int x, int y) {
return matrix[x][y];
}
public void set(int x, int y, float value) {
matrix[x][y] = value;
}
public String toString() {
String matrix = "";
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
matrix += (Float.toString(get(i, j)) + ", ");
}
matrix += "\n";
}
return matrix + "";
}
}
Camera Class
package engine.rendering;
import engine.maths.Matrix4f;
import engine.maths.Vector3f;
public class Camera {
private Vector3f position, rotation;
public Camera(Vector3f position, Vector3f rotation) {
this.position = position;
this.rotation = rotation;
}
public Matrix4f getViewMatrix() {
Matrix4f rotationMatrix = new Matrix4f().identity().rotate(rotation);
Vector3f negativePosition = new Vector3f(-position.getX(), -position.getY(), -position.getZ());
Matrix4f translationMatrix = new Matrix4f().identity().translate(negativePosition);
return rotationMatrix.mul(translationMatrix);
}
public void addPosition(float x, float y, float z) {
position.add(new Vector3f(x, y, z));
}
public void addPosition(Vector3f value) {
position.add(value);
}
public void setPosition(float x, float y, float z) {
position = new Vector3f(x, y, z);
}
public void setPosition(Vector3f pos) {
position = pos;
}
public Vector3f getPosition() {
return position;
}
public void addRotation(float x, float y, float z) {
rotation.add(new Vector3f(x, y, z));
}
public void addRotation(Vector3f value) {
rotation.add(value);
}
public void setRotation(float x, float y, float z) {
rotation = new Vector3f(x, y, z);
}
public void setRotation(Vector3f rot) {
rotation = rot;
}
public Vector3f getRotation() {
return rotation;
}
}
Loading Matrix Class
package engine.shaders;
import engine.maths.Matrix4f;
public class BasicShader extends Shader {
private static final String VERTEX_FILE = "src/engine/shaders/basicVertexShader.glsl";
private static final String FRAGMENT_FILE = "src/engine/shaders/basicFragmentShader.glsl";
private int tvpMatrixLocation;
private Matrix4f transformationMatrix = new Matrix4f().identity(), projectionMatrix = new Matrix4f().identity(), viewMatrix = new Matrix4f().identity();
public BasicShader() {
super(VERTEX_FILE, FRAGMENT_FILE);
}
#Override
protected void bindAttributes() {
super.bindAttribute(0, "position");
super.bindAttribute(1, "textCoords");
}
#Override
protected void getAllUniforms() {
tvpMatrixLocation = super.getUniform("tvpMatrix");
}
public void useMatrices() {
super.loadMatrixUniform(tvpMatrixLocation, transformationMatrix.mul(projectionMatrix.mul(viewMatrix)));
}
public void loadTransformationMatrix(Matrix4f matrix) {
transformationMatrix = matrix;
}
public void loadProjectionMatrix(Matrix4f matrix) {
projectionMatrix = matrix;
}
public void loadViewMatrix(Matrix4f matrix) {
viewMatrix = matrix;
}
}
Your projection matrix has a fault: matrix[3][2] = 1 must be -1.
This is due to OpenGL NDC space is special, cross product XxY gives -Z instead of Z.
The surprising fact is that all visible objects must have a negative Z-coordinate in view space.
This is not making any sense:
super.loadMatrixUniform(tvpMatrixLocation, transformationMatrix.mul(projectionMatrix.mul(viewMatrix)));
No matter what conventions you use, and which order the mul() method actually multiplies. you either end up with T*P*V, or V*P*T, which both woudln't be correct (for the typical use case of not applying some additional transformation after the projection).
I just started working with LibGDX and can't figure out how to hide an image when it collides with an object. In my game some dots come from the top of the screen and meet the dot at the bottom. When they meet the dots should hide that isn't happening.
This is the main Game Class
public class GameScreen implements Screen,InputProcessor {
final AmazingDot game;
//setting the height and width variables
private int height;
private int width;
private static int touchCounter;
//setting the two dots variables
private Texture playerDotImage;
private Texture gameDotImage;
private Texture gameDotImage1;
private Rectangle playerDotRectangle;
private Map<Rectangle,Texture> gameDotMap;
//storing the time of last dot in nano seconds
private long lastDotTime;
public GameScreen(final AmazingDot gam){
this.game = gam;
Gdx.input.setInputProcessor(this);
//getting the height and width of the user's screen
height = Gdx.graphics.getHeight();
width = Gdx.graphics.getWidth();
touchCounter =0;
//loading the images in the variables
playerDotImage = new Texture(Gdx.files.internal("images/dot2.png"));
gameDotImage = new Texture(Gdx.files.internal("images/dot1.png"));
gameDotImage1 = new Texture(Gdx.files.internal("images/dot2.png"));
//placing the player dot in the middle of the screen
playerDotRectangle = new Rectangle();
playerDotRectangle.x = width/ 2 - 64 / 2;
playerDotRectangle.y = 20;
playerDotRectangle.width = 64;
playerDotRectangle.height = 64;
gameDotMap = new ConcurrentHashMap<Rectangle, Texture>();
populateDots();
}
private void populateDots(){
Rectangle dots = new Rectangle();
dots.x = randomLocation();
dots.y = height;
dots.width = 64;
dots.height = 64;
Random rand = new Random();
int n = rand.nextInt(2) + 1;
if(n==1){
gameDotMap.put(dots,gameDotImage1);
}
else{
gameDotMap.put(dots,gameDotImage);
}
lastDotTime = TimeUtils.nanoTime();
}
private int randomLocation(){
int[] locations = new int[3];
locations[0]=0;
locations[1]=width/2-64/2;
locations[2]=width-64;
Random generator = new Random();
int randomIndex = generator.nextInt(locations.length);
return locations[randomIndex];
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
game.batch.draw(playerDotImage,playerDotRectangle.x,playerDotRectangle.y,playerDotRectangle.width,playerDotRectangle.height);
for(Map.Entry<Rectangle,Texture> dots : gameDotMap.entrySet()){
game.batch.draw(dots.getValue(),dots.getKey().x,dots.getKey().y);
}
game.batch.end();
// check if we need to create a new dot
if(TimeUtils.nanoTime() - lastDotTime > 1000000000) populateDots();
for(Rectangle dot : gameDotMap.keySet()){
int gameSpeed = 400;
int xSpeed = calXSpeed(gameSpeed);
dot.y = dot.y - gameSpeed * Gdx.graphics.getDeltaTime();
if(dot.x <width/2-64/2){
dot.x = dot.x + xSpeed*Gdx.graphics.getDeltaTime();
}
else if(dot.x>width/2-64/2){
dot.x = dot.x - xSpeed*Gdx.graphics.getDeltaTime();
}
if(dot.y + 64 < 0) gameDotMap.remove(dot);
if(dot.overlaps(playerDotRectangle)) {
//this is where I am trying to remove the map object on collision
gameDotMap.remove(dot);
}
}
}
private int calXSpeed(int gameSpeed){
int seconds = height/gameSpeed;
int distance = width/2-64/2;
int speed = distance/seconds;
return speed;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
touchCounter++;
if(touchCounter % 2==0){
playerDotImage = new Texture(Gdx.files.internal("images/dot2.png"));
}
else{
playerDotImage = new Texture(Gdx.files.internal("images/dot1.png"));
}
return true;
}
#Override
public void dispose() {
playerDotImage.dispose();
gameDotImage.dispose();
gameDotImage1.dispose();
}
}
EDIT
As you can see in the above image when the moving dot reaches the stationary dot, it should disappear. But here in my code the dot just moves past the stationary dot. I am using rectangles(LibGdx) to detect whether the dots overlap each other or not.
Define you Map as an ArrayMap like so:
private ArrayMap<Rectangle, Texture> gameDotMap;
Then you can rewrite you render method like this:
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.begin();
game.batch.draw(playerDotImage, playerDotRectangle.x, playerDotRectangle.y, playerDotRectangle.width, playerDotRectangle.height);
for (int i = 0; i < gameDotMap.size; i++) {
game.batch.draw(gameDotMap.getValueAt(i), gameDotMap.getKeyAt(i).x, gameDotMap.getKeyAt(i).y);
}
game.batch.end();
// check if we need to create a new dot
if (TimeUtils.nanoTime() - lastDotTime > 1000000000) {
populateDots();
}
for (Iterator<ObjectMap.Entry<Rectangle, Texture>> iter = gameDotMap.iterator(); iter.hasNext();) {
ObjectMap.Entry<Rectangle, Texture> entry = iter.next();
Rectangle dot = entry.key;
int gameSpeed = 400;
int xSpeed = calXSpeed(gameSpeed);
dot.y = dot.y - gameSpeed * Gdx.graphics.getDeltaTime();
if (dot.x < width / 2 - 64 / 2) {
dot.x = dot.x + xSpeed * Gdx.graphics.getDeltaTime();
} else if (dot.x > width / 2 - 64 / 2) {
dot.x = dot.x - xSpeed * Gdx.graphics.getDeltaTime();
}
if (dot.y + 64 < 0) {
iter.remove();
}
if (dot.overlaps(playerDotRectangle)) {
//this is where I am trying to remove the map object on collision
iter.remove();
}
}
}
LibGDX has specific types for collections, they are recommended over the JDK's collections.
Here I have use 'HoloGraph' Library for Doughnut chart But Now I need to show with animation. Please suggest me How can I do it?
I have done without animation
Here's how i finally did it after two days of search with help of this library https://github.com/Ken-Yang/AndroidPieChart
And equations to center text done with help of my friends and alot of search
on MainActivity onCreate or oncreateView if you are using fragments:
PieChart pie = (PieChart) rootView.findViewById(R.id.pieChart);
ArrayList<Float> alPercentage = new ArrayList<Float>();
alPercentage.add(2.0f);
alPercentage.add(8.0f);
alPercentage.add(20.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.0f);
alPercentage.add(10.85f);
alPercentage.add(9.15f);
try {
// setting data
pie.setAdapter(alPercentage);
// setting a listener
pie.setOnSelectedListener(new OnSelectedLisenter() {
#Override
public void onSelected(int iSelectedIndex) {
Toast.makeText(getActivity(),
"Select index:" + iSelectedIndex,
Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
if (e.getMessage().equals(PieChart.ERROR_NOT_EQUAL_TO_100)) {
Log.e("kenyang", "percentage is not equal to 100");
}
}
public class PieChart extends View {
public interface OnSelectedLisenter {
public abstract void onSelected(int iSelectedIndex);
}
private OnSelectedLisenter onSelectedListener = null;
private static final String TAG = PieChart.class.getName();
public static final String ERROR_NOT_EQUAL_TO_100 = "NOT_EQUAL_TO_100";
private static final int DEGREE_360 = 360;
private static String[] PIE_COLORS = null;
private static int iColorListSize = 0;
ArrayList<Float> array;
private Paint paintPieFill;
private Paint paintPieBorder;
private Paint paintCenterCircle;
private ArrayList<Float> alPercentage = new ArrayList<Float>();
private int mCenterX = 320;
private int mCenterY = 320;
private int iDisplayWidth, iDisplayHeight;
private int iSelectedIndex = -1;
private int iCenterWidth = 0;
private int iShift = 0;
private int iMargin = 0; // margin to left and right, used for get Radius
private int iDataSize = 0;
private Canvas canvas1;
private RectF r = null;
private RectF centerCircle = null;
private float fDensity = 0.0f;
private float fStartAngle = 0.0f;
private float fEndAngle = 0.0f;
float fX;
float fY;
public PieChart(Context context, AttributeSet attrs) {
super(context, attrs);
PIE_COLORS = getResources().getStringArray(R.array.colors);
iColorListSize = PIE_COLORS.length;
array = new ArrayList<Float>();
fnGetDisplayMetrics(context);
iShift = (int) fnGetRealPxFromDp(30);
iMargin = (int) fnGetRealPxFromDp(40);
centerCircle = new RectF(200, 200, 440, 440);
// used for paint circle
paintPieFill = new Paint(Paint.ANTI_ALIAS_FLAG);
paintPieFill.setStyle(Paint.Style.FILL);
// used for paint centerCircle
paintCenterCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
paintCenterCircle.setStyle(Paint.Style.FILL);
paintCenterCircle.setColor(Color.WHITE);
// used for paint border
paintPieBorder = new Paint(Paint.ANTI_ALIAS_FLAG);
paintPieBorder.setStyle(Paint.Style.STROKE);
paintPieBorder.setStrokeWidth(fnGetRealPxFromDp(3));
paintPieBorder.setColor(Color.WHITE);
Log.i(TAG, "PieChart init");
}
// set listener
public void setOnSelectedListener(OnSelectedLisenter listener) {
this.onSelectedListener = listener;
}
float temp = 0;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i(TAG, "onDraw");
float centerX = (r.left + r.right) / 2;
float centerY = (r.top + r.bottom) / 2;
float radius1 = (r.right - r.left) / 2;
radius1 *= 0.5;
float startX = mCenterX;
float startY = mCenterY;
float radius = mCenterX;
float medianAngle = 0;
Path path = new Path();
for (int i = 0; i < iDataSize; i++) {
// check whether the data size larger than color list size
if (i >= iColorListSize) {
paintPieFill.setColor(Color.parseColor(PIE_COLORS[i
% iColorListSize]));
} else {
paintPieFill.setColor(Color.parseColor(PIE_COLORS[i]));
}
fEndAngle = alPercentage.get(i);
// convert percentage to angle
fEndAngle = fEndAngle / 100 * DEGREE_360;
// if the part of pie was selected then change the coordinate
if (iSelectedIndex == i) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
float fAngle = fStartAngle + fEndAngle / 2;
double dxRadius = Math.toRadians((fAngle + DEGREE_360)
% DEGREE_360);
fY = (float) Math.sin(dxRadius);
fX = (float) Math.cos(dxRadius);
canvas.translate(fX * iShift, fY * iShift);
}
canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieFill);
float angle = (float) ((fStartAngle + fEndAngle / 2) * Math.PI / 180);
float stopX = (float) (startX + (radius/2) * Math.cos(angle));
float stopY = (float) (startY + (radius/2) * Math.sin(angle));
// if the part of pie was selected then draw a border
if (iSelectedIndex == i) {
canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieBorder);
canvas.drawLine(startX, startY, stopX, stopY, paintPieFill);
canvas.restore();
}
fStartAngle = fStartAngle + fEndAngle;
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// get screen size
iDisplayWidth = MeasureSpec.getSize(widthMeasureSpec);
iDisplayHeight = MeasureSpec.getSize(heightMeasureSpec);
if (iDisplayWidth > iDisplayHeight) {
iDisplayWidth = iDisplayHeight;
}
/*
* determine the rectangle size
*/
iCenterWidth = iDisplayWidth / 2;
int iR = iCenterWidth - iMargin;
if (r == null) {
r = new RectF(iCenterWidth - iR, // top
iCenterWidth - iR, // left
iCenterWidth + iR, // right
iCenterWidth + iR); // bottom
}
if (centerCircle == null) {
// centerCircle=new RectF(left, top, right, bottom);
}
setMeasuredDimension(iDisplayWidth, iDisplayWidth);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// get degree of the touch point
double dx = Math.atan2(event.getY() - iCenterWidth, event.getX()
- iCenterWidth);
float fDegree = (float) (dx / (2 * Math.PI) * DEGREE_360);
fDegree = (fDegree + DEGREE_360) % DEGREE_360;
// get the percent of the selected degree
float fSelectedPercent = fDegree * 100 / DEGREE_360;
// check which pie was selected
float fTotalPercent = 0;
for (int i = 0; i < iDataSize; i++) {
fTotalPercent += alPercentage.get(i);
if (fTotalPercent > fSelectedPercent) {
iSelectedIndex = i;
break;
}
}
if (onSelectedListener != null) {
onSelectedListener.onSelected(iSelectedIndex);
}
invalidate();
return super.onTouchEvent(event);
}
private void fnGetDisplayMetrics(Context cxt) {
final DisplayMetrics dm = cxt.getResources().getDisplayMetrics();
fDensity = dm.density;
}
private float fnGetRealPxFromDp(float fDp) {
return (fDensity != 1.0f) ? fDensity * fDp : fDp;
}
public void setAdapter(ArrayList<Float> alPercentage) throws Exception {
this.alPercentage = alPercentage;
iDataSize = alPercentage.size();
float fSum = 0;
for (int i = 0; i < iDataSize; i++) {
fSum += alPercentage.get(i);
}
if (fSum != 100) {
Log.e(TAG, ERROR_NOT_EQUAL_TO_100);
iDataSize = 0;
throw new Exception(ERROR_NOT_EQUAL_TO_100);
}
}
In Layout:
<com.example.piecharts.PieChart
android:id="#+id/pieChart"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</com.example.piecharts.PieChart>
I have drawn a bar chart without xml.I have to add a button below the graph.Can anybody suggest solution.Thanks in Advance!!Following is my program.
GraphViewDemo.java
public class GraphViewDemo extends Activity {
public static String graphreturn;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
float[] values = new float[] { 2.0f,3.0f, 5.0f, 1.0f , 6.0f , 4.0f ,7.0f };
String[] verlabels = new String[] { "7","6","5","4","3", "2", "1" };
String[] horlabels = new String[] {"jan20","jan21","jan22","jan23","jan24",
"jan25","jan26"};
GraphView graphView = new GraphView(this, values, "GraphViewDemo",horlabels, verlabels, GraphView.BAR);
setContentView(graphView);}}
GraphView.java
public class GraphView extends View{
public static boolean BAR = true;
public static boolean LINE = false;
private Paint paint;
private float[] values;
private String[] horlabels;
private String[] verlabels;
private String title;
private boolean type;
Context context;
private Drawable mDrawable;
private Runnable in ;
public GraphView(Context context, float[] values, String title, String[] horlabels,String[] verlabels, boolean type) {
super(context);
if (values == null)
values = new float[0];
else
this.values = values;
if (title == null)
title = "";
else
this.title = title;
if (horlabels == null)
this.horlabels = new String[0];
else
this.horlabels = horlabels;
if (verlabels == null)
this.verlabels = new String[0];
else
this.verlabels = verlabels;
this.type = type;
paint = new Paint();
}
#Override
protected void onDraw(final Canvas canvas) {
context=getContext();
float border = 20;
float horstart = border * 2;
float height = getHeight()-50;
float width = getWidth();
float max = getMax();
Log.w("max", ""+max);
float min = getMin();
Log.w("min", ""+min);
float diff = max - min;
float graphheight = height - (2 * border);
float graphwidth = width - (2 * border);
paint.setTextAlign(Align.LEFT);
int vers = verlabels.length - 1;
for (int i = 0; i < verlabels.length; i++) {
paint.setColor(Color.DKGRAY);
float y = ((graphheight / vers) * i) + border;
canvas.drawLine(horstart, y, width, y, paint);
paint.setColor(Color.WHITE);
canvas.drawText(verlabels[i], 0, y, paint);
}
int hors = horlabels.length;
for (int i = 0; i < horlabels.length; i++) {
paint.setColor(Color.DKGRAY);
float x = ((graphwidth / hors) * i) + horstart;
canvas.drawLine(x, height - border, x, border, paint);
paint.setTextAlign(Align.CENTER);
if (i==horlabels.length+5)
paint.setTextAlign(Align.RIGHT);
if (i==0)
paint.setTextAlign(Align.LEFT);
paint.setColor(Color.WHITE);
canvas.drawText(horlabels[i], x, height - 4, paint);
}
paint.setTextAlign(Align.CENTER);
canvas.drawText(title, (graphwidth / 2) + horstart, border - 4, paint);
int x = 0;
int y = 0;
Paint paint = new Paint();
Paint paint1 = new Paint();
paint.setStyle(Paint.Style.FILL);
String str2rotate = "Rotated!";
// draw bounding rect before rotating text
Rect rect = new Rect();
paint.getTextBounds(str2rotate, 0, str2rotate.length(), rect);
canvas.translate(x, y);
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.STROKE);
paint1.setColor(Color.RED);
canvas.drawText("!Rotated", 0, 0, paint1);
mDrawable = context.getResources().getDrawable(R.drawable.previousi);
mDrawable.setBounds(getWidth()/2-40,getHeight()-40, getWidth()/2+30, getHeight()-20);
mDrawable.draw(canvas);
mDrawable.scheduleSelf(in, 0);
//....................
in = new Runnable() {
public void run() {
try {
//canvas.restore();
mDrawable.setBounds(getWidth()/2,getHeight(), getWidth(), getHeight()-20);
mDrawable.draw(canvas);
}
catch (Exception e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(null, in, "graphview");
thread.start();
if (max != min) {
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.FILL);
if (type == BAR) {
float datalength = values.length;
float colwidth = (width - (2 * border)) / datalength;
for (int i = 0; i < values.length; i++) {
float val = values[i] - min;
float rat = val / diff;
float h = graphheight * rat;
canvas.drawRect((i * colwidth) + horstart, (border - h) + graphheight, ((i * colwidth) + horstart) + (colwidth - 1), height - (border - 1), paint);
}
} else {
float datalength = values.length;
float colwidth = (width - (2 * border)) / datalength;
float halfcol = colwidth / 2;
float lasth = 0;
for (int i = 0; i < values.length; i++) {
float val = values[i] - min;
float rat = val / diff;
float h = graphheight * rat;
if (i > 0)
canvas.drawLine(((i - 1) * colwidth) + (horstart + 1) + halfcol, (border - lasth) + graphheight, (i * colwidth) + (horstart + 1) + halfcol, (border - h) + graphheight, paint);
lasth = h;
}
}
}
}
private float getMax() {
float largest = Integer.MIN_VALUE;
for (int i = 0; i < values.length; i++)
if (values[i] > largest)
largest = values[i];
return largest;
}
private float getMin() {
float smallest = Integer.MAX_VALUE;
for (int i = 0; i < values.length; i++)
if (values[i] < smallest)
smallest = values[i];
return smallest;
}
}
Try this:
btn = new Button(this);
btn.setText("Hello Button");
RelativeLayout.LayoutParams paramsd = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONT ENT,LayoutParams.WRAP_CONTENT);
paramsd.height = 60;
paramsd.width = 60;
btn.setLayoutParams(paramsd);
addContentView(btn,paramsd);
Edit:
import android.widget.Button;
Add button
Button b = new Button(this);
b.setText("Button added dynamically!");
b.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
b.setId(MY_BUTTON);
b.setOnClickListener(this);
ll.addView(b);
Edit2:
You could create LinearLayout linearLayout = new LinearLayout(this); and add Button
Button btn = new Button(this);
btn.setText("Just another button");
linearLayout.addView(btn);
Edit3: another example:
final Button button = new Button(this);
button.setText("Press me!");
setContentView(button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
Huh? Just use XML. That you have this custom view is no barrier to its use. Here is a quick example of normal Android widgets in a layout with a custom widget:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tileview="http://schemas.android.com/apk/res/net.rapacity.wizardry"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/sokostatus"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/sokoban_status"/>
<net.rapacity.wizardry.TileView
android:id="#+id/sokomaze"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tileview:tileSize="32"/>
</LinearLayout>