Wrong coordinates for different objects - java

In short:
I create Polygon object with a help of this method:
public static float[][] getPolygonArrays(float cx, float cy, float R, int sides) {
float[] x = new float[sides];
float[] y = new float[sides];
double thetaInc = 2 * Math.PI / sides;
double theta = (sides % 2 == 0) ? thetaInc : -Math.PI / 2;
for (int j = 0; j < sides; j++) {
x[j] = (float) (cx + R * Math.cos(theta));
y[j] = (float) (cy + R * Math.sin(theta));
theta += thetaInc;
}
return new float[][]{x, y};
}
and merge it to one dimension array with:
public static float[] mergeCoordinates(float[][] vertices) throws Exception {
if (vertices.length != 2 || vertices[0].length != vertices[1].length) throw new Exception("No valid data");
ArrayList<Float> mergedArrayList = new ArrayList<Float>();
float[] mergedArray = new float[vertices[0].length * 2];
for(int i = 0; i < vertices[0].length; i++) {
mergedArrayList.add(vertices[0][i]);
mergedArrayList.add(vertices[1][i]);
}
int i = 0;
for (Float f : mergedArrayList) {
mergedArray[i++] = (f != null ? f : Float.NaN);
}
return mergedArray;
}
I use 0 as value for X and Y for all newly created Polygons (named in code as Platform). And result of method mergeCoordinates i pass to method setVertices of Polygon object.
After this step i do setPosition with x = Gdx.graphics.getWidth()/2 and y = Gdx.graphics.getHeight()/2. Polygons are positioned good, right on the game screen center.
Than i create a new one Polygon, which must use origin coordinates from first Polygon object, this new polygon i named Figure. To set origin coordinates i use method setOrigin of Polygon class, and use X and Y of Platform Polygon object.
When i run method rotate of Platform Polygon object i also rotate Figure Polygon object, and Figure must rotate around origin point, center of Platform. But it does not.
Figure do rotation around bottom right corner.
For example:
my screen size is 640 x 480. Center point will be 320 x 240. This is X and Y of Platform Polygon object, i checked it with getX and getY of Polygon. I create Figure at 0,0, do setPosition(320, 200) (this is preferred orbit distance for figure to platform). And Figure positioned also good.
I run setOrigin(320, 240) for Figure Polygon Object.
I run rotate for Figure object. And it somehow think that right bottom corner have coordinates x = 320 and y = 240 and do rotation around this point.
Any could help me to solve this problem?
More details on problem you can find below(details, images, gifs, schemes and also sources).
More detailed part starts here
i'm trying to understand how coordinate system in libgdx work, cause i have a problem with positioning objects in game world.
I created simple application, with one big Red Polygon object(Platform in code),
10 White Triangle Polygons(Sector in code) which are included into big polygon object and inherits it's behavior(such like rotate, moveTo and etc).
Than i added inside each Sector one Green Polyline(Direction in code) from first vertice of Sector Polygon to midle point of the opposite side to first point.
This is technical line and i will use it's vertices(coordinates of two points) to move small Red Polygon Object(Figure in code), from center to oposite side to center point of Sector.
When i click on Stage and click coordinates are inside Platform i rotate it to the left or to the right(depends on where click was made). On rotate all Sectors and technical lines are rotated correctly.
http://i.imgur.com/s5xaI8j.gif
(670Kb)
As you can see on gif, figures rotates around theire's center point. I found that Polygon class has method setOrigin(float x, float y) and in annotation to this method said next:
/** Sets the origin point to which all of the polygon's local vertices
are relative to. */
So i tried to use this method, set origin X of Figure as center X of Platform and origin Y as center Y of Platform, and tried to rotate Platform.
http://i.imgur.com/pXpTuQi.gif
(1.06Mb)
As you can see, Figure polygon think that his origin coordinates are at right bottom corner. And Figure do rotation around right bottom corner.
I changed origin to next values: x = 50 and y = 50, here is a result:
http://i.imgur.com/Iajb9sN.gif
(640Kb)
I cannot get why it behave like that. What should i change in my logic?
I have not much classes in my project. I removed all imports and getters/setter to reduce amount of lines.
If it is necessary i could provide entire project.
GameScreen code:
public class GameScreen extends DefaultScreen {
private final GameWorld world;
private final GameRenderer renderer;
public GameScreen() {
world = new GameWorld();
renderer = new GameRenderer(world);
}
#Override
public void render(float delta) {
world.update(delta);
renderer.render();
}
#Override
public void resize(int width, int height) {
world.resize(width, height);
}
}
GameWorld code:
public class GameWorld {
private ArrayList < Platform > platforms = new ArrayList < Platform > ();
private OrthographicCamera camera;
private Stage stage;
private Array < Figure > activeFigures;
private Pool < Figure > figuresPool;
private long lastFigureTime = TimeUtils.nanoTime();
public GameWorld() {
setCamera(new OrthographicCamera());
getCamera().setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
setStage(new Stage());
getStage().setViewport(new ScreenViewport(getCamera()));
initializePools();
createPlatforms();
getStage().addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
float degrees = Config.PLATFORM_ROTATE_DEGREES;
if (x <= Gdx.graphics.getWidth() / 2) {
degrees *= -1;
}
int i = getPlatforms().size();
while (i-- > 0) {
Platform platform = getPlatforms().get(i);
if (!platform.isLocked() && platform.isRotatable() && platform.getShape().getPolygon().contains(x, y)) {
platform.addAction(Actions.rotateBy(degrees, 1, Interpolation.bounceOut));
break;
}
}
return true;
}
});
Gdx.input.setInputProcessor(getStage());
}
private void initializePools() {
setActiveFigures(new Array < Figure > ());
setFiguresPool(new Pool < Figure > () {#Override
protected Figure newObject() {
return new Figure();
}
});
}
private void createPlatforms() {
float max = Gdx.graphics.getHeight() / (Gdx.graphics.getWidth() / (Gdx.graphics.getWidth() / 2));
float x = Gdx.graphics.getWidth() / 2;
float y = Gdx.graphics.getHeight() / 2;
float sides = 10f;
Color color = Color.RED;
createPlatform(x, y, max * Config.THIRD_PLATFORM_RADIUS_MULTIPLIER, sides, color, true, false, false, null);
}
private Platform createPlatform(float x, float y, float radius, float sides, Color color, boolean rotatable, boolean locked, boolean isEmpty, Platform relatedTo) {
Platform platform = new Platform(0, 0, radius, sides, color, isEmpty, this);
platform.moveTo(x, y);
platform.setRotatable(rotatable);
platform.setLocked(locked);
getPlatforms().add(platform);
getStage().addActor(platform);
if (relatedTo != null) {
relatedTo.addRelation(platform);
}
return platform;
}
private Figure createFigure(float x, float y) {
Figure figure = getFiguresPool().obtain();
figure.init(this, 0, 0, 10f, 4f, Color.DARK_GRAY);
figure.moveTo(x, y);
getActiveFigures().add(figure);
getStage().addActor(figure);
return figure;
}
public void spawnFigure() {
if (getActiveFigures().size >= 10) return;
if (TimeUtils.nanoTime() - getLastFigureTime() <= 2000000000) return;
Platform platform = null;
for (Platform p: getPlatforms()) {
if (!p.isEmpty()) {
platform = p;
break;
}
}
if (platform == null) {
setLastFigureTime(TimeUtils.nanoTime());
return;
}
Sector sector = platform.getSectors().get(MathUtils.random(platform.getSectors().size() - 1));
float x = platform.getX();
float y = platform.getY();
Figure figure = createFigure(x, y);
figure.origin(x, y);
x = sector.getDirection().getTransformedVertices()[2];
y = sector.getDirection().getTransformedVertices()[3];
figure.addAction(Actions.moveTo(x, y, 1));
setLastFigureTime(TimeUtils.nanoTime());
}
public void update(float delta) {
updatePlatforms(delta);
updateFigures(delta);
spawnFigure();
}
private void updatePlatforms(float delta) {
for (Platform platform: getPlatforms()) {
platform.update(delta);
}
}
private void updateFigures(float delta) {
Figure figure;
int figures = getActiveFigures().size;
for (int i = figures; --i >= 0;) {
figure = getActiveFigures().get(i);
if (figure.isAlive() == false) {
getActiveFigures().removeIndex(i);
getFiguresPool().free(figure);
} else {
figure.update(delta);
}
}
}
public void resize(int width, int height) {
getCamera().setToOrtho(true, width, height);
getStage().getViewport().update(width, height, true);
for (Platform platform: getPlatforms()) {
platform.resize(true, width, height);
}
for (Figure figure: getActiveFigures()) {
figure.resize(true, width, height);
}
}
}
GameRenderer code:
public class GameRenderer {
private ShapeRenderer shapeRenderer;
private GameWorld world;
private SpriteBatch spriteBatch;
public GameRenderer(GameWorld world) {
setWorld(world);
setShapeRenderer(new ShapeRenderer());
getShapeRenderer().setProjectionMatrix(getWorld().getCamera().combined);
setSpriteBatch(new SpriteBatch());
getSpriteBatch().setProjectionMatrix(getWorld().getCamera().combined);
}
public void render() {
Gdx.gl.glClearColor(0f, 0.2f, 0.4f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
getWorld().getCamera().update();
getSpriteBatch().setProjectionMatrix(getWorld().getCamera().combined);
getShapeRenderer().setProjectionMatrix(getWorld().getCamera().combined);
getWorld().getStage().act(Gdx.graphics.getDeltaTime());
getWorld().getStage().draw();
renderGameObjects();
}
private void renderGameObjects() {
renderPlatforms();
renderFigures();
}
private void renderFigures() {
getShapeRenderer().begin(ShapeRenderer.ShapeType.Line);
for (Figure figure: getWorld().getActiveFigures()) {
figure.render(getSpriteBatch(), getShapeRenderer());
}
getShapeRenderer().end();
}
private void renderPlatforms() {
getShapeRenderer().begin(ShapeRenderer.ShapeType.Line);
for (Platform platform: world.getPlatforms()) {
platform.render(getSpriteBatch(), getShapeRenderer());
}
getShapeRenderer().end();
}
}
Platform code:
public class Platform extends GameObject {
private ArrayList < Sector > sectors = new ArrayList < Sector > ();
private ArrayList < Platform > relations = new ArrayList < Platform > ();
private boolean rotatable = true;
private boolean locked = false;
private void initialize(float cx, float cy, float radius, float sides, Color color) {
setPosition(cx, cy);
setRadius(radius);
setShape(ShapeType.POLYGON.getInstance(new float[] {
cx, cy, radius, sides
}, color));
}
public Platform(float cx, float cy, float radius, float sides, Color color, boolean isEmpty, GameWorld gameWorld) {
setGameWorld(gameWorld);
initialize(cx, cy, radius, sides, color);
setEmpty(isEmpty);
if (!isEmpty()) {
generateSectors();
}
}
private void generateSectors() {
float[] vertices = getShape().getVertices();
for (int i = 0; i < vertices.length; i += 2) {
try {
Color color = Color.WHITE;
if (i + 3 > vertices.length) {
getSectors().add(new Sector(new float[] {
getX(), getY(), vertices[i], vertices[i + 1], vertices[0], vertices[1]
}, color, this, i / 2));
} else {
getSectors().add(new Sector(new float[] {
getX(), getY(), vertices[i], vertices[i + 1], vertices[i + 2], vertices[i + 3]
}, color, this, i / 2));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void rotateBy(float degrees) {
setRotation(degrees);
getShape().rotate(degrees);
for (Sector sector: getSectors()) {
sector.rotate(degrees);
}
for (Platform platform: getRelations()) {
platform.rotateBy(degrees);
}
for (Figure figure: getGameWorld().getActiveFigures()) {
figure.rotate(degrees);
}
}
#Override
public void moveTo(float x, float y) {
super.moveTo(x, y);
getShape().moveTo(x, y);
for (Sector sector: getSectors()) {
sector.moveTo(x, y);
}
for (Platform platform: getRelations()) {
platform.moveTo(x, y);
}
}
public void addRelation(Platform platform) {
if (platform.equals(this)) return;
getRelations().add(platform);
}
#Override
public void update(float delta) {
for (Sector sector: getSectors()) {
sector.update(delta);
}
}
#Override
public void dispose() {
for (Sector sector: getSectors()) {
sector.dispose();
}
}
#Override
public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
render(spriteBatch);
if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
for (Sector sector: getSectors()) {
sector.render(spriteBatch, shapeRenderer);
}
}
private void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(getShape().getColor());
shapeRenderer.polygon(getShape().getVertices());
}
public void resize(boolean reposition, int width, int height) {
if (reposition) {
moveTo(width / 2, height / 2);
}
}
}
Sector code:
public class Sector extends GameObject {
private Polyline direction;
private float[] vertices;
private Platform platform;
private int sectorId;
public Sector(float[] vertices, Color color, Platform platform, int sectorId) throws Exception {
setSectorId(sectorId);
setVertices(vertices);
initialize(vertices, color, platform);
}
private void createDirection() {
float[] vertices = getShape().getPolygon().getVertices();
float x1 = vertices[0];
float y1 = vertices[1];
float x2 = (vertices[2]+vertices[4])/2;
float y2 = (vertices[3]+vertices[5])/2;
setDirection(new Polyline(new float[]{ x1, y1, x2, y2 }));
}
public Sector(float[] vertices, Color color, boolean isEmpty) throws Exception {
initialize(vertices, color);
setEmpty(isEmpty);
}
private void initialize(float[] vertices, Color color) throws Exception {
if (vertices.length != 6) {
throw new Exception("Sector constructor expects 6 vertices");
}
setShape(ShapeType.TRIANGLE.getInstance(vertices, color));
createDirection();
}
private void initialize(float[] vertices, Color color, Platform platform) throws Exception {
if (vertices.length != 6) {
throw new IllegalArgumentException("Sector constructor expects 6 vertices");
}
setShape(ShapeType.TRIANGLE.getInstance(vertices, color));
setPlatform(platform);
createDirection();
}
public void rotate(float degrees) {
getShape().rotate(degrees);
getDirection().rotate(degrees);
}
#Override
public void moveTo(float x, float y) {
super.moveTo(x, y);
getShape().moveTo(x, y);
getDirection().setPosition(x, y);
}
#Override
public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
render(spriteBatch);
if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
}
private void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(getShape().getColor());
shapeRenderer.polygon(getShape().getVertices());
shapeRenderer.setColor(Color.GREEN);
shapeRenderer.line(getDirection().getTransformedVertices()[0], getDirection().getTransformedVertices()[1], getDirection().getTransformedVertices()[2], getDirection().getTransformedVertices()[3]);
}
}
Figure code:
public class Figure extends GameObject {
private GameWorld world;
public void init(GameWorld world, float cx, float cy, float radius, float sides, Color color) {
super.init();
setWorld(world);
initialize(cx, cy, radius, sides, color);
}
private void initialize(float cx, float cy, float radius, float sides, Color color) {
super.moveTo(cx, cy);
setRadius(radius);
setShape(ShapeType.POLYGON.getInstance(new float[] {
cx, cy, radius, sides
}, color));
}
#Override
public void moveTo(float x, float y) {
super.moveTo(x, y);
getShape().moveTo(x, y);
}
#Override
public void setPosition(float x, float y) {
if (!isAllowedToFlyFuther()) {
clearActions();
return;
}
moveTo(x, y);
}
private boolean isAllowedToFlyFuther() {
for (Figure figure: getWorld().getActiveFigures()) {
if (!figure.equals(this) && Intersector.overlapConvexPolygons(figure.getShape().getPolygon(), getShape().getPolygon())) {
return false;
}
}
return true;
}
#Override
public void reset() {
super.reset();
remove();
}
#Override
public void update(float delta) {}
private void render(SpriteBatch spriteBatch) {}
#Override
public void dispose() {}
#Override
public void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer) {
render(spriteBatch);
if (Config.DEBUG_LAYOUTS) render(shapeRenderer);
}
private void render(ShapeRenderer shapeRenderer) {
shapeRenderer.setColor(getShape().getColor());
shapeRenderer.polygon(getShape().getVertices());
}
public void rotate(float degrees) {
setRotation(degrees);
getShape().rotate(degrees);
}
public void origin(float originX, float originY) {
setOrigin(originX, originY);
getShape().setOrigin(originX, originY);
}
public void resize(boolean reposition, int width, int height) {
if (reposition) {
//TODO: implement reposition for figures
}
}
}
GameObject code:
public abstract class GameObject extends Actor implements Poolable {
private int speed = 200;
private int baseSpeed = 200;
private boolean alive;
private float radius;
private GameWorld gameWorld;
private Shape shape;
private boolean empty = false;
public GameObject() {
setAlive(false);
}
public void init() {
setAlive(true);
}
public void reset() {
setAlive(false);
}
public abstract void update(float delta);
public abstract void render(SpriteBatch spriteBatch, ShapeRenderer shapeRenderer);
public abstract void dispose();
public void moveTo(float x, float y) {
super.setPosition(x, y);
}
}
Shape code:
public class Shape {
private Color color = new Color(Color.RED);
private float[] vertices;
private int sides;
private float radius;
private Polygon polygon = new Polygon();
public void rotate(float degrees) {
getPolygon().rotate(degrees);
setVertices(getPolygon().getTransformedVertices());
}
public void moveTo(float x, float y) {
getPolygon().setPosition(x, y);
setVertices(getPolygon().getTransformedVertices());
}
public void setOrigin(float originX, float originY) {
getPolygon().setOrigin(originX, originY);
setVertices(getPolygon().getTransformedVertices());
}
public void scale(float ratio) {
getPolygon().setScale(ratio, ratio);
setVertices(getPolygon().getTransformedVertices());
}
}
ShapeType code:
public enum ShapeType {
POLYGON {#Override
public Shape getInstance(float[] settings, Color color) {
try {
return new PolygonShape(settings, color);
} catch (Exception e) {
e.printStackTrace();
}
return new BaseShape();
}
},
TRIANGLE {#Override
public Shape getInstance(float[] settings, Color color) {
try {
return new TriangleShape(settings, color);
} catch (Exception e) {
e.printStackTrace();
}
return new BaseShape();
}
};
public abstract Shape getInstance(float[] settings, Color color);
}
PolygonShape code:
public class PolygonShape extends Shape {
public PolygonShape(float[] settings, Color color) throws Exception {
if (settings.length < 4) {
throw new IllegalArgumentException("Polygon shape constructor expects minimum 4 items in settings");
}
setSides((int) settings[3]);
setRadius(settings[2]);
setVertices(Utils.mergeCoordinates(Utils.getPolygonArrays(settings[0], settings[1], settings[2], (int) settings[3])));
getPolygon().setVertices(getVertices());
}
}
TriangleShape code:
public class TriangleShape extends Shape {
public TriangleShape(float[] settings, Color color) throws Exception {
if (settings.length < 6) {
throw new IllegalArgumentException("Triangle shape constructor expects minimum 6 items in settings");
}
setVertices(settings);
setColor(color);
getPolygon().setVertices(getVertices());
}
}
Utils code:
public class Utils {
public static float[] mergeCoordinates(float[][] vertices) throws Exception {
if (vertices.length != 2 || vertices[0].length != vertices[1].length) throw new Exception("No valid data");
ArrayList < Float > mergedArrayList = new ArrayList < Float > ();
float[] mergedArray = new float[vertices[0].length * 2];
for (int i = 0; i < vertices[0].length; i++) {
mergedArrayList.add(vertices[0][i]);
mergedArrayList.add(vertices[1][i]);
}
int i = 0;
for (Float f: mergedArrayList) {
mergedArray[i++] = (f != null ? f : Float.NaN);
}
return mergedArray;
}
public static float[][] getPolygonArrays(float cx, float cy, float R, int sides) {
float[] x = new float[sides];
float[] y = new float[sides];
double thetaInc = 2 * Math.PI / sides;
double theta = (sides % 2 == 0) ? thetaInc : -Math.PI / 2;
for (int j = 0; j < sides; j++) {
x[j] = (float)(cx + R * Math.cos(theta));
y[j] = (float)(cy + R * Math.sin(theta));
theta += thetaInc;
}
return new float[][] {
x, y
};
}
}
Config code:
public class Config {
public static final String LOG = TheGame.class.getSimpleName();
public static final boolean DEBUG_LAYOUTS = true;
public static final boolean SHOW_LOG = false;
public static final float PLATFORM_ROTATE_DEGREES = 36;
}
DesktopLauncher code:
public class DesktopLauncher {
public static void main(String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title = "The Game!";
config.width = 1920 / 3;
config.height = 1080 / 3;
new LwjglApplication(new TheGame(), config);
}
}
Project structure:
Platform object structure and dependencies:
Render objects workflow

Related

Efficient way to draw paint using mouse on canvas

I have a Brush class
final class Brush
{
private final int size;
private final Color color;
private final Ellipse2D.Double blob=new Ellipse2D.Double();
private Brush(int size,Color color)
{
this.size=size;
this.color=color;
}
void paint(Graphics2D g2d,Point location)
{
g2d.setColor(color);
blob.setFrame(location.x-(size/2.0),location.y-(size/2.0),size,size);//Translate ecllipse so that the centre of it's bounding box is exactly at the cursor location for more accurate blobs
g2d.fill(blob);
}
}
I have a Blob class which keeps track of the user's current brush settings and where the user previously dragged his mouse so as to remember to draw a blob there.
final class Blob
{
final Brush brush;
final Point location;
private Blob(Brush brush,Point location)
{
this.brush=brush;
this.location=location;
}
private void paint(Graphics2D g){brush.paint(g,location);}
}
Finally my paint logic which is very simple.
Whenever the user drags his mouse add a blob at that current location with the current brush settings and inside paint() loop through all blobs and redraw them.
final class Painter extends Canvas
{
private Brush brush=new Brush(5,Color.red);//Can Change
private final ArrayList<Blob> blobs=new ArrayList();
private Painter(){addMouseMotionListener(new Dragger());}
#Override
public void paint(Graphics g)
{
super.paint(g);
blobs.forEach(blob->blob.paint(g));
}
private final class Dragger extends MouseAdapter
{
#Override
public void mouseDragged(MouseEvent m)
{
blobs.add(brush,m.getPoint());
repaint();
}
}
}
You can already see the problem here. The size of the list grows exponentially and my app quickly slows down. Is there an more efficient way to do this?
The much more efficient way to do this is to use a BufferedImage for your drawing, and than painting the BufferedImage in paintComponent
Code taken from PaintArea:
public void paintComponent(Graphics g) {
if (mSizeChanged) {
handleResize();
}
g.drawImage(mImg, 0, 0, null);
}
protected class MListener extends MouseAdapter implements MouseMotionListener {
Point mLastPoint;
public void mouseDragged(MouseEvent me) {
Graphics g = mImg.getGraphics();
if ((me.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
g.setColor(mColor1);
} else {
g.setColor(mColor2);
}
Point p = me.getPoint();
if (mLastPoint == null) {
g.fillOval(p.x - mBrushSize / 2, p.y - mBrushSize / 2, mBrushSize, mBrushSize);
//g.drawLine(p.x, p.y, p.x, p.y);
}
else {
g.drawLine(mLastPoint.x, mLastPoint.y, p.x, p.y);
//g.fillOval(p.x - mBrushSize / 2, p.y - mBrushSize / 2, mBrushSize, mBrushSize);
double angle = MathUtils.angle(mLastPoint, p);
if (angle < 0) {
angle += 2 * Math.PI;
}
#SuppressWarnings("unused")
double distance = MathUtils.distance(mLastPoint, p) * 1.5;
if (angle < Math.PI / 4 || angle > 7 * Math.PI / 4 || Math.abs(Math.PI - angle) < Math.PI / 4) {
for (int i = 0; i < mBrushSize / 2; i ++) {
g.drawLine(mLastPoint.x, mLastPoint.y + i, p.x, p.y + i);
g.drawLine(mLastPoint.x, mLastPoint.y - i, p.x, p.y - i);
}
}
else {
for (int i = 0; i < mBrushSize / 2; i ++) {
g.drawLine(mLastPoint.x + i, mLastPoint.y, p.x + i, p.y);
g.drawLine(mLastPoint.x - i, mLastPoint.y, p.x - i, p.y);
}
}
}
mLastPoint = p;
g.dispose();
repaint();
}
public void mouseMoved(MouseEvent me) {}
public void mouseReleased(MouseEvent me) {
mLastPoint = null;
}
}

Multiple balls - Bouncing balls - Java

I am wring the bouncing ball program in java. And I Now have one bouncing ball, I would like to have at least five bouncing balls. I have tried a few ways to do it, however, I only end up with one ball or error.
Do you have any suggestions on how to proceed? This in the piece of code used for the one ball, is it possible to rewrite this piece of code to get multiple balls in a neat way?
import javafx.scene.shape.Rectangle;
public class World {
private final double width, height;
private Ball[] balls;
private final Rectangle pad;
public World(double width, double height) {
this.width = width;
this.height = height;
balls = new Ball[1];
balls[0] = new Ball(10, 10);
balls[0].setVelocity(75.0, 100.0);
pad = new Rectangle(width / 2, 0.9 * height,
width / 8, height / 32);
}
public void move(long elapsedTimeNs) {
balls[0].move(elapsedTimeNs);
constrainBall(balls[0]);
checkForCollisionWithPad(balls[0]);
}
public Ball[] getBalls() {
return (Ball[]) balls.clone();
}
public Rectangle getPad() {
return pad;
}
public void setPadX(double x) {
if (x > width) {
x = width;
}
if (x < 0) {
x = 0;
}
pad.setX(x);
}
private void constrainBall(Ball ball) {
double x = ball.getX(), y = ball.getY();
double dx = ball.getDx(), dy = ball.getDy();
double radius = ball.getRadius();
if (x < radius) {
dx = Math.abs(dx);
} else if (x > width - radius) {
dx = -Math.abs(dx);
}
if (y < radius) {
dy = Math.abs(dy);
} else if (y > height - radius) {
dy = -Math.abs(dy);
}
ball.setVelocity(dx, dy);
}
private void checkForCollisionWithPad(Ball ball) {
if (ball.intersectsArea(
pad.getX(), pad.getY(), pad.getWidth(), pad.getHeight())) {
double dx = ball.getDx();
// set dy negative, i.e. moving "up"
double newDy = -Math.abs(ball.getDy());
ball.setVelocity(dx, newDy);
}
}
}
Main
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Alert;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Bounce extends Application {
private World world;
private Canvas canvas;
private AnimationTimer timer;
protected class BounceTimer extends AnimationTimer {
private long previousNs = 0;
#Override
public void handle(long nowNs) {
if (previousNs == 0) {
previousNs = nowNs;
}
world.move(nowNs - previousNs);
previousNs = nowNs;
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.WHITESMOKE);
gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
Rectangle pad = world.getPad();
gc.setFill(Color.BLACK);
double x = pad.getX(), y = pad.getY(),
w = pad.getWidth(), h = pad.getHeight();
gc.fillRoundRect(x, y, w, h, h, h);
for (Ball b : world.getBalls()) {
b.paint(gc);
}
}
}
#Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 300, 300, Color.WHITESMOKE);
canvas = new Canvas(scene.getWidth(), scene.getHeight());
root.getChildren().add(canvas);
stage.setTitle("Bounce");
stage.setScene(scene);
stage.setResizable(false);
stage.sizeToScene();
stage.show();
world = new World(canvas.getWidth(), canvas.getHeight());
timer = new BounceTimer();
timer.start();
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent me) {
world.setPadX(me.getX());
}
});
}
public static void main(String[] args) {
launch(args);
}
private void showAlert(String message) {
alert.setHeaderText("");
alert.setTitle("Alert!");
alert.setContentText(message);
alert.show();
}
private final Alert alert = new Alert(Alert.AlertType.INFORMATION);
}
Ball
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class Ball {
public static final double BILLION = 1_000_000_000.0;
private double x, y; // position of the balls center
private double dx, dy; // velocity measured in pixels/second
private double radius;
private Color color;
public Ball(double x0, double y0) {
x = x0;
y = y0;
radius = 10;
color = Color.MAGENTA;
}
public Ball(double x0, double y0, double rad, Color col) {
x = x0;
y = y0;
radius = rad;
color = col;
}
Ball(int i, int i0, Color BLUEVIOLET) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setColor(Color col) { // setColor
color = col; }
public double getX() {
return x;
}
public double getY() {
return y;
}
public void setX(double newX) {
x = newX;
}
public void setY(double newY) {
y = newY;
}
public double getRadius() {
return radius;
}
public double getDx() {
return dx;
}
public double getDy() {
return dy;
}
public void setVelocity(double newDx, double newDy) {
dx = newDx;
dy = newDy;
}
public void moveTo(double newX, double newY) {
x = newX;
y = newY;
}
public void move(long elapsedTimeNs) {
x += dx * elapsedTimeNs / BILLION;
y += dy * elapsedTimeNs / BILLION;
}
public void paint(GraphicsContext gc) {
gc.setFill(color);
// arguments to fillOval: see the javadoc for GraphicsContext
gc.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
public boolean intersectsArea(
double rectX, double rectY,
double rectWidth, double rectHeight) {
double closestX = clamp(x, rectX, rectX + rectWidth);
double closestY = clamp(y, rectY, rectY + rectHeight);
double distanceX = x - closestX;
double distanceY = y - closestY;
return (distanceX * distanceX) + (distanceY * distanceY)
< (radius * radius);
}
private double clamp(double value, double lower, double upper) {
if (value < lower) {
return lower;
}
if (value > upper) {
return upper;
}
return value;
}
}
As Stormblessed said, you are only targeting one ball in your move method.
You should do:
public void move(Ball ball, long elapsedTimeNs) {
ball.move(elapsedTimeNs);
constrainBall(ball);
checkForCollisionWithPad(ball);
}
Edit: Since you want the handler method to accept only the elapsedTimeNs argument, do:
public void move(long elapsedTimeNs) {
for (Ball ball : balls) {
ball.move(elapsedTimeNs);
constrainBall(ball);
checkForCollisionWithPad(ball);
}
}
Edit 2: You should probably have a method that creates a new ball, for convenience:
public Ball newBall(double x, double y, double velocity1, double velocity2) {
Ball tmp = new Ball(x, y);
tmp.setVelocity(velocity1, velocity2);
balls.add(tmp);
return tmp;
}
Edit 3: The reason it throws an error is that you designated balls to have only one index position by using balls = new Ball[1]. You should use an ArrayList (java.util.ArrayList) instead, like so:
import java.util.ArrayList;
ArrayList<Ball> balls = new ArrayList<>;
You should now use balls.add and balls.get instead of = and []. References have been updated accordingly.

LibGDX Flip 2D Sprite Animation

I have an animation that I want to play flipped if the user presses the 'A' key on their keyboard. The animation is facing right in the file and is played normally until I try to flip the texture.
This is what happens when I try to flip the texture when the player's direction has changed:
As you can see, the animation plays fine in the beginning but when I change the player's direction it alternates between the flipped frame and the unflipped frame.
This is my player class:
package unit22.game;
import java.util.ArrayList;
import unit22.core.Utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class Player {
private PlayerState state = PlayerState.STANDING;
private Direction direction = Direction.RIGHT;
private int x = 0, y = 0, width = 0, height = 0;
private PlayerInputProcessor inputProcessor;
private String name;
private ArrayList<Action> actions;
private Animation standingAnim;
private Animation movingAnim;
private float stateTime;
private SpriteBatch spriteBatch;
private Action currentAction;
private Animation currentAnimation;
public Player(String name, int x, int y, int width, int height) {
this.name = name;
setBounds(x, y, width, height);
if(getX() > 400) setDirection(Direction.LEFT);
this.actions = new ArrayList<Action>();
standingAnim = new Animation(0.06f, Utils.loadTextureAtlas("standing", "textures/characters/animations/" + name + "/").getRegions());
//movingAnim = new Animation(0.06f, Utils.loadTextureAtlas("moving", "textures/characters/animations/" + name + "/").getRegions());
stateTime = 0f;
spriteBatch = new SpriteBatch();
}
public void update() {
stateTime += Gdx.graphics.getDeltaTime();
switch(state) {
case STANDING:
if(currentAnimation != standingAnim)
currentAnimation = standingAnim;
break;
case MOVING:
if(currentAnimation != movingAnim)
currentAnimation = movingAnim;
break;
case ACTING:
Animation anim = new Animation(0.06f, Utils.loadTextureAtlas(currentAction.getName(), "textures/characters/animations/" + getName() + "/").getRegions());
if(currentAnimation != anim)
currentAnimation = anim;
break;
}
}
public void render() {
TextureRegion currentFrame = currentAnimation.getKeyFrame(stateTime, true);
if(getDirection() == Direction.LEFT) {
currentFrame.flip(true, false);
}
System.out.println("Direction: " + direction + ", Flipped: " + currentFrame.isFlipX());
spriteBatch.begin();
spriteBatch.draw(currentFrame, x, y, width, height);
spriteBatch.end();
}
public ArrayList<Action> getActions() {
return actions;
}
public void addAction(Action action) {
this.actions.add(action);
}
public void setActions(ArrayList<Action> actions) {
this.actions = actions;
}
public void setInputProcessor(PlayerInputProcessor inputProcessor) {
this.inputProcessor = inputProcessor;
}
public PlayerInputProcessor getInputProcessor() {
return inputProcessor;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Direction getDirection() {
return direction;
}
public PlayerState getState() {
return state;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public void setState(PlayerState state) {
this.state = state;
}
public int[] getBounds() {
return new int[] {x, y, width, height};
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void setBounds(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
}
In my render method I am checking whether the player's direction is left and if it is then to flip the current animation frame.
This is how I am handling my input:
package unit22.screens;
import unit22.core.Game;
import unit22.core.Screen;
import unit22.game.Direction;
import unit22.game.Player;
import unit22.game.PlayerInputProcessor;
import com.badlogic.gdx.Gdx;
public class Playing extends Screen {
Player player;
public Playing(Game game, String name) {
super(game, name);
}
#Override
public void init() {
player = new Player("misaka", 100, 100, 188, 380);
player.setInputProcessor(new PlayerInputProcessor(player) {
#Override
public boolean keyTyped(char character) {
if(getPlayer().getX() <= 14) getPlayer().setX(15);
if(getPlayer().getX() + getPlayer().getWidth() >= 1024 - getPlayer().getWidth()) getPlayer().setX(1024 - getPlayer().getWidth() - 15);
if(character == 'a' || character == 'A') {
getPlayer().setX((int)(getPlayer().getX() - (900 * Gdx.graphics.getDeltaTime())));
if(getPlayer().getDirection() == Direction.RIGHT) {
getPlayer().setDirection(Direction.LEFT);
}
}
if(character == 'd' || character == 'D') {
getPlayer().setX((int)(getPlayer().getX() + (900 * Gdx.graphics.getDeltaTime())));
if(getPlayer().getDirection() == Direction.LEFT) {
getPlayer().setDirection(Direction.RIGHT);
}
}
return super.keyTyped(character);
}
});
getInputHandle().addProcessor(player.getInputProcessor());
}
#Override
public void render(float delta) {
super.render(delta);
player.update();
player.render();
}
}
I've been trying to figure this problem out for a couple of hours now and haven't made any progress. Any idea why this would be happening?
The problem is here:
if(getDirection() == Direction.LEFT) {
currentFrame.flip(true, false);
}
The flip method permanently flips the original TextureRegion that the Animation class is referencing. So you either need to make sure you flip it back each time after flipping and drawing it, or do this, which I think is simpler:
Never flip it but instead use a negative width when drawing it with SpriteBatch, like this:
boolean flip = (getDirection() == Direction.LEFT);
spriteBatch.draw(currentFrame, flip ? x+width : x, y, flip ? -width : width, height);
If somebody is still wondering, negating scaleX or scaleY works like a charm and does not hurt performance (like TextureRegion.flip does for example).
Example:
draw(region, x, y, originX, originY, width, float height,
(flip ? -1 : 1) * scaleX, float scaleY, float rotation);
I know that question is old but I think it is better solution
currentFrame = walkAnimation.getKeyFrame(stateTime, true);
if(!currentFrame.isFlipX())
currentFrame.flip(true, false);
batch.draw(currentFrame, 0,0,0,0);
I flip my animation sequence use the code below(in kotlin):
if (this.position <= 0f)
{
this.speed = - this.speed
this.position = 0.0f
this.runAnimation.keyFrames.forEach {
it.flip(true, false)
}
}else if(this.position >= SCREEN_WIDTH / SCALE - width)
{
this.speed = - this.speed
this.position = SCREEN_WIDTH / SCALE - width
this.runAnimation.keyFrames.forEach {
it.flip(true, false)
}
}
this.game.batch.begin()
this.game.batch.draw(currentFrame, this.position, 40f)
this.game.batch.end()
Every time you flip the sequence, make sure loop every frame and flip every one:
this.runAnimation.keyFrames.forEach { it.flip(true, false) }
and remember that, the frames are flipped forever, so if you want to return back, you should flip again(flip = true)!

LibGDX: How to get the same coordinates in tiled map for tile with and without zoom

I am a beginner with LibGDX. I am trying to create an android game based fixed size tiled map (33x21 tiles). Tiles I am using are 32x32px. So far I managed to load the map created with Tiled and add touch gestures like zoom in/out and panning. The game character movement will be turn based tile by tile, so I need to have a possibility to select specific tile in order to perform some action. I tried solution from here: LibGDX: How to make tiled map tiles clickable? and it works perfectly fine, until the screen is not zoomed in.
Without zoom, the left-bottom corner coordinates shows that it is (0,0), which is correct. When I zoom in, the left-bottom corner of the visible part of the map instead of keeping it's correct coordinates (i.e. (480, 320)) it becomes (0,0) again. I tried to use camera.unproject(Vector3), but I was unsuccessful. Probably used it wrong. I am also not really convinced, that the way in which I try to get tiles is the most appropriate one. Can you help me get tiles coordinates properly? Below is the code that I am using:
public class TiledTest extends ApplicationAdapter {
public TiledMap tiledMap;
OrthographicCamera camera;
TiledMapRenderer tiledMapRenderer;
GestureDetector gesture;
InputMultiplexer myInputMultiplexer;
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
public static final float PAN_RATE = (float) 0.01;
private static final float ZOOM_SPEED = (float) 0.009;
int columns, rows;
TiledMapTileLayer grid_layer;
#Override
public void create () {
gesture =new GestureDetector(new MyGestureListener());
myInputMultiplexer = new InputMultiplexer();
float unitScale = 1 / 32f;
camera = new OrthographicCamera();
camera.setToOrtho(true, 33,21);
tiledMap = new TmxMapLoader().load("tiled_map.tmx");
tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, unitScale);
grid_layer = (TiledMapTileLayer)tiledMap.getLayers().get(0);
Stage stage = new TiledMapStage(tiledMap);
myInputMultiplexer.addProcessor(gesture);
myInputMultiplexer.addProcessor(stage);
Gdx.input.setInputProcessor(myInputMultiplexer);
}
#Override
public void render () {
tiledMapRenderer.setView(camera);
tiledMapRenderer.render();
camera.update();
}
public class TiledMapActor extends Actor {
private TiledMapTileLayer.Cell cell;
public TiledMapActor(TiledMap tileMap, TiledMapTileLayer tiledLayer, TiledMapTileLayer.Cell cell) {
tiledMap = tileMap;
grid_layer = tiledLayer;
this.cell = cell;
}
}
public class TiledMapClickListener extends ClickListener {
private TiledMapActor actor;
public TiledMapClickListener(TiledMapActor actor) {
this.actor = actor;
}
#Override
public void clicked(InputEvent event, float x, float y) {
int a = (int) actor.getX();
int b = (int) actor.getY();
System.out.println(actor.cell + " has been clicked.");
System.out.println("x = " + a + "y = " + b );
}
}
public class TiledMapStage extends Stage {
private TiledMap tiledMap;
public TiledMapStage(TiledMap tiledMap) {
this.tiledMap = tiledMap;
for (MapLayer layer : tiledMap.getLayers()) {
TiledMapTileLayer tiledLayer = (TiledMapTileLayer)layer;
createActorsForLayer(tiledLayer);
}
}
private void createActorsForLayer(TiledMapTileLayer tiledLayer) {
for (int x = 0; x <= tiledLayer.getWidth(); x++) {
for (int y = 0; y < tiledLayer.getHeight(); y++) {
TiledMapTileLayer.Cell cell = tiledLayer.getCell(x, y);
TiledMapActor actor = new TiledMapActor(tiledMap, tiledLayer, cell);
actor.setBounds(x * tiledLayer.getTileWidth(), y * tiledLayer.getTileHeight(), tiledLayer.getTileWidth(),
tiledLayer.getTileHeight());
addActor(actor);
EventListener eventListener = new TiledMapClickListener(actor);
actor.addListener(eventListener);
}
}
}
}
public void resize(float width, float height) {
}
public class MyGestureListener implements GestureListener{
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
return false;
}
#Override
public boolean tap(float x, float y, int count, int button) {
return false;
}
#Override
public boolean longPress(float x, float y) {
return false;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
return false;
}
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
float effectiveViewportWidth = camera.viewportWidth * camera.zoom;
float effectiveViewportHeight = camera.viewportHeight * camera.zoom;
camera.position.x = MathUtils.clamp(camera.position.x, effectiveViewportWidth / 2f, 33 - effectiveViewportWidth / 2f);
camera.position.y = MathUtils.clamp(camera.position.y, effectiveViewportHeight / 2f, 21 - effectiveViewportHeight / 2f);
if (camera.zoom < 1) {
camera.translate(-deltaX * PAN_RATE, -deltaY * PAN_RATE, 0);
camera.update();
}
return false;
}
#Override
public boolean panStop(float x, float y, int pointer, int button) {
//Gdx.app.log("Text", "panstop");
return false;
}
#Override
public boolean zoom (float originalDistance, float currentDistance){
float ratio = originalDistance/currentDistance;
camera.zoom += ZOOM_SPEED * ratio;
if (camera.zoom < 0.3)
{
camera.zoom = (float) 0.3;
}
else if (camera.zoom > 1)
{
camera.zoom = 1;
}
System.out.println(camera.zoom);
return false;
}
#Override
public boolean pinch (Vector2 initialFirstPointer, Vector2 initialSecondPointer, Vector2 firstPointer, Vector2 secondPointer){
camera.zoom -= .01;
camera.update();
return false;
}
}
}
So you want to transfer the screen coordinates to world coordinates.
For example:
#Override
public void clicked(InputEvent event, float x, float y) {
Vector3 touch = new Vector3(x, y, 0);
camera.unproject(touch);
System.out.println("Screen coordinates translated to world coordinates: "
+ "X: " + touch.x + " Y: " + touch.y);
}
}
Above clicked function does not worked for me, but you led me to the answer. I dumped whole assigning actors for tiles and used camera.unproject in MyGestureListener in touchDown.
If someone is interested I just leave it here :)
#Override
public boolean touchDown(float x, float y, int pointer, int button) {
Vector3 temp_coord = new Vector3(x,y,0);
Vector3 coords = camera.unproject(temp_coord);
x =(int) coords.x;
y =(int) coords.y;
writerX = x;
writerY = y;
System.out.println("Screen coordinates translated to world coordinates: "
+ "X: " + x + " Y: " + y);
return false;
}

My ellipse creating program is only creating lines

I have a program that makes an ellipse when you click somewhere on a JPanel. When I did a test run, it just made slanted lines to the right of where I clicked. Can anyone find the problem? Thanks, here is the code:
This is the code for the click:
final SpriteField mSpritePanel = new SpriteField();
mSpritePanel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
float tX = e.getX();
float tY = e.getY();
int tIntWidth;
int tIntHeight;
int tIntRotate = 0;
if(tTextWidth.getText() == null)
{
tTextWidth.setText("50");
}
try
{
tIntWidth = Integer.parseInt(tTextWidth.getText());
}
catch(NumberFormatException ex)
{
tIntWidth = 50;
}
if(tIntWidth == 0)
{
tIntWidth = 50;
}
if(tTextHeight.getText() == null)
{
tTextHeight.setText("50");
}
try
{
tIntHeight = Integer.parseInt(tTextHeight.getText());
}
catch(NumberFormatException ex)
{
tIntHeight = 50;
}
if(tIntHeight == 0)
{
tIntHeight = 50;
}
if(tTextRotation.getText() == null)
{
tTextRotation.setText("0");
}
try
{
tIntRotate = Integer.parseInt(tTextRotation.getText());
}
catch(NumberFormatException ex)
{
tIntRotate = 50;
}
mSpritePanel.CreateSpriteAt(tX, tY, tIntWidth, tIntHeight, tIntRotate);
mSpritePanel.repaint();
}
});
This is the code for my SpriteField class:
public class SpriteField extends JPanel
{
final List<RoundSprite> mSpriteList = new ArrayList<RoundSprite>();
public void CreateSpriteAt(float tX, float tY, int tWidth, int tHeight, int tRotation)
{
RoundSprite mSprite = new RoundSprite();
mSprite.SetPosition(tX, tY);
mSprite.SetSpriteWidth(tWidth);
mSprite.SetSpriteHeight(tHeight);
mSprite.SetSpriteRotation(tRotation);
mSpriteList.add(mSprite);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
AffineTransform originalTransform = g2.getTransform();
for (RoundSprite mSprite : mSpriteList)
{
mSprite.DrawSprite(g2);
g2.setTransform(originalTransform);
}
}
}
And this is the code for my RoundSprite class:
public class RoundSprite
{
private float mX;
private float mY;
int mWidth;
int mHeight;
int mRotate;
Color mColor;
void DrawSprite(Graphics2D g2)
{
AffineTransform tOldTransform = g2.getTransform();
g2.setColor(mColor);
g2.translate(mX, mY);
g2.rotate(mRotate);
g2.translate(mX - (mWidth / 2), mY - (mHeight / 2));
g2.draw(new Ellipse2D.Double(0, 0, mWidth, mHeight));
g2.setTransform(tOldTransform);
}
public void SetSpriteWidth(int tWidth)
{
mWidth = tWidth;
}
public void SetSpriteHeight(int tHeight)
{
mWidth = tHeight;
}
public void SetSpriteColor(Color tColor)
{
mColor = tColor;
}
public void SetPosition(float x, float y)
{
mX = x;
mY = y;
}
public void SetSpriteRotation(int tRotate)
{
mRotate = tRotate;
}
}
You've got a copy-paste error in your setters for RoundSprite:
public void SetSpriteWidth(int tWidth)
{
mWidth = tWidth; // set the width
}
public void SetSpriteHeight(int tHeight)
{
mWidth = tHeight; // set the width again, leaving mHeight forever 0...
}
This leaves all of your ellipses one-dimensional, so they render as a line.
Just make it mHeight = tHeight instead and your program will work.
Update to respond to the comment on ellipse location
In the RoundSprite#DrawSprite() method you are calling g2.translate() twice. g2.translate() is a relative, not absolute position change, so you don't want to give the mouse coordinates the second time you call it.
replace this:
g2.translate(mX - (mWidth / 2), mY - (mHeight / 2));
with this:
g2.translate(-mWidth/2, -mHeight/2);
to center the ellipse around the mouseclick location.

Categories

Resources