libgdx making my physics upside down? - java

For some reason when I use the same code in a previous physics test without libgdx it works fine. But with libgdx it thinks the ground is in the sky.
package com.me.randomtests;
import com.badlogic.gdx.ApplicationListener;
import...
public class Randomtest implements ApplicationListener {
ShapeRenderer SR;
int x = 100, y = 100, radius = 10;
double deltax = 0, deltay = 0, gravity = 15, energyloss = .65, dt = .2;
#Override
public void create() {
SR=new ShapeRenderer();
}
#Override
public void dispose() {
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
SR.begin(ShapeType.FilledCircle);
SR.filledCircle(x, y, radius);
SR.setColor(Color.BLUE);
SR.end();
Update();
}
public void Update(){
System.out.println(y);
if(x + deltax > Gdx.graphics.getWidth() - radius -1 ){
x = Gdx.graphics.getWidth() - radius - 1;
deltax = - deltax;
}else if(x + deltax < 0 + radius){
x = 0+radius;
deltax= - deltax;
}else{
x += deltax;
}
if(y>Gdx.graphics.getHeight() - radius - 1){
y = Gdx.graphics.getHeight() - radius - 1;
deltay *=.9;
deltay = -deltay;
}else{
//vel formuka
deltay += gravity *dt;
//pos formula
y +=deltay*dt + .5*gravity*dt*dt;
}
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
what is my problem here? Also does anyone know why 0 is at the bottom with libgdx?

Related

Libgdx - Rotate an object using its movement

I'm trying to implement an autorotation method for a SpriteAnimation class (trying to port SpriteAnimation).
Everything is working, the sprite draws correctly (it uses the correct animations) it just doesn't rotate properly if at all, normally it seems to point to the origin (0, 0) only after its target matches its position while I want its rotation to update as it moves, i've tried both degrees and radians, neither of which work. It should be rotating to match the current direction it's going. I've been struggling with this for about a week now, but still have not gotten the desired result.
Full Code Here
Relevant code:
From SpriteAnimation
// The x position of the sprite's upper left corner pixel.
public int getX() { return (int)position.x; }
public void setX(int value)
{
prevPosition.x = position.x;
position.x = value;
updateRotation();
}
// The y position of the sprite's upper left corner pixel.
public int getY() { return (int)position.y; }
public void setY(int value)
{
prevPosition.y = position.y;
position.y = value;
updateRotation();
}
void updateRotation()
{
if (rotateByPosition)
{
Vector2 rotationVector = new Vector2(position.x - prevPosition.x, position.y - prevPosition.y);
rotationRad = rotationVector.angle();
rotationDeg = rotationRad * MathUtils.radiansToDegrees;
}
}
public void MoveBy(int x, int y)
{
prevPosition = new Vector2(position);
position.x += x;
position.y += y;
updateRotation();
}
public void Update(float deltaTime)
{
// Don't do anything if the sprite is not animating
if (animating)
{
// If there is not a currently active animation
if (getCurrentFrameAnimation() == null)
{
// Make sure we have an animation associated with this sprite
if (animations.size() > 0)
{
// Set the active animation to the first animation
// associated with this sprite
String[] sKeys = new String[animations.size()];
int index = 0;
for (Entry<String, FrameAnimation> mapEntry : animations.entrySet()) {
sKeys[index] = mapEntry.getKey();
index++;
}
setCurrentAnimation(sKeys[0]);
}
else
{
return;
}
}
// Run the Animation's update method
getCurrentFrameAnimation().Update(deltaTime);
// Check to see if there is a "follow-up" animation named for this animation
if (getCurrentFrameAnimation().getNextAnimation() != null && !getCurrentFrameAnimation().getNextAnimation().isEmpty())
{
// If there is, see if the currently playing animation has
// completed a full animation loop
if (getCurrentFrameAnimation().getPlayCount() > 0)
{
// If it has, set up the next animation
setCurrentAnimation(getCurrentFrameAnimation().getNextAnimation());
}
}
}
}
public void Draw(SpriteBatch spriteBatch, int xOffset, int yOffset)
{
updateRotation(); // Calling this while testing to make sure that it is being called
spriteBatch.draw(getCurrentTextureRegion(), getPosition().x + xOffset - center.x, getPosition().y + yOffset - center.y, center.x, center.y, getCurrentFrameAnimation().getFrameWidth(), getCurrentFrameAnimation().getFrameHeight(), 1.0f, 1.0f, rotationRad);
}
TestScreen class
package com.darkstudio.darkisle.screens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.darkstudio.darkisle.DarkIsle;
import com.delib.engine.sprite.MobileSprite;
/**
* Created by DarkEnder on 2017/06/27.
*/
public class TestScreen implements Screen {
final DarkIsle game;
OrthographicCamera camera;
Texture tankTexture;
MobileSprite mouseTank;
public TestScreen(final DarkIsle game)
{
this.game = game;
camera = new OrthographicCamera();
configureCamera();
tankTexture = new Texture(Gdx.files.internal("MulticolorTanks.png"));
mouseTank = new MobileSprite(tankTexture, 32, 32);
mouseTank.getSprite().AddAnimation("red", 0, 32, 32, 32, 8, 0.1f);
mouseTank.getSprite().AddAnimation("purple", 0, 128, 32, 32, 8, 0.1f, "red");
mouseTank.getSprite().AddAnimation("yellow", 0, 64, 32, 32, 8, 0.1f);
mouseTank.getSprite().setAutoRotate(true);
mouseTank.setPosition(new Vector2(100, 100));
mouseTank.setTarget(new Vector2(mouseTank.getPosition()));
mouseTank.setIsPathing(true);
mouseTank.setEndPathAnimation("yellow");
mouseTank.setLoopPath(false);
mouseTank.setSpeed(2);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
update();
game.batch.begin();
mouseTank.draw(game.batch);
game.batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
private void configureCamera()
{
Vector3 camPos = new Vector3(camera.position);
float size = 800;
float cameraWidth = 0;
float cameraHeight = 0;
if (Gdx.graphics.getHeight() < Gdx.graphics.getWidth())
{
cameraWidth = size;
cameraHeight = size * Gdx.graphics.getHeight() / Gdx.graphics.getWidth();
}
else
{
cameraWidth = size * Gdx.graphics.getWidth() / Gdx.graphics.getHeight();
cameraHeight = size;
}
camera.setToOrtho(true, cameraWidth, cameraHeight);
camera.position.set(camPos.x + camera.viewportWidth / 2f, camPos.y + camera.viewportHeight / 2f, 0);
}
private void update() {
int xTouch = Gdx.input.getX(0);
int yTouch = Gdx.input.getY(0);
mouseTank.setTarget(xTouch, yTouch);
mouseTank.update(Gdx.graphics.getDeltaTime());
}
}
Edit: Just saying now that I've already tried using atan2 in MathUtils and it gave the same results.
The MobileSprite update method
public void update(float deltaTime)
{
if (active && movingTowardsTarget)
{
if ((target != null))
{
// Get a vector pointing from the current location of the sprite
// to the destination.
Vector2 Delta = new Vector2(target.x - sprite.getX(), target.y - sprite.getY());
if (Delta.len() > getSpeed())
{
Delta.nor();
Delta.scl(getSpeed());
getPosition().add(Delta);
}
else
{
if (target == sprite.getPosition())
{
if (pathing)
{
if (queuePath.size() > 0)
{
target = queuePath.remove();
if (loopPath)
{
queuePath.remove(target);
}
}
else
{
if (!(endPathAnimation == null))
{
if (!(getSprite().getCurrentAnimation() == endPathAnimation))
{
getSprite().setCurrentAnimation(endPathAnimation);
}
}
if (deactivateAtEndOfPath)
{
setIsActive(false);
}
if (hideAtEndOfPath)
{
setIsVisible(false);
}
}
}
}
else
{
sprite.setPosition(target);
}
}
}
}
if (active)
sprite.Update(deltaTime);
}
To get the radians angle:
void updateRotation()
{
if (rotateByPosition)
{
Vector2 rotationVector = new Vector2(position.x - prevPosition.x, position.y - prevPosition.y);
rotationRad = rotationVector.angleRad();
rotationDeg = rotationRad * MathUtils.radiansToDegrees;
}
}
and the draw method needs a degrees angle:
spriteBatch.draw(
getCurrentTextureRegion(),
getPosition().x + xOffset - center.x,
getPosition().y + yOffset - center.y,
center.x, center.y,
getCurrentFrameAnimation().getFrameWidth(), getCurrentFrameAnimation().getFrameHeight(),
1.0f, 1.0f,
rotationDeg
);
The screen mouse position is from the upper left corner the renderer needs from the bottom left corner:
int xTouch = Gdx.input.getX(0);
int yTouch = Gdx.graphics.getHeight() - Gdx.input.getY(0);

Why do i have to initialize the ball in Resize() method? - Libgdx

I'm making a simple Bouncing Ball game, even if i call the init() method via BouncingBall class constructor in Show() method of the BallScreen class, the ball isn't created. So to create a ball, i should call BouncingBall's init() method in Resize() method. Why? Isn't it supposed to be created in Show() method ?
Here is the code for Bouncing Ball
public class BouncingBall {
public static final float RADIUS_RATIO = 0.04f;
public static final float START_KICK = 500.0f;
private static final float KICK_INTERVAL = 3f;
private static final float DRAG = 1f;
private Vector2 position;
private Vector2 velocity;
float radius;
float lastKick;
public BouncingBall(Viewport viewport) {
init(viewport);
}
public void init(Viewport viewport) {
position = new Vector2();
position.x = viewport.getWorldWidth() / 2;
position.y = viewport.getWorldHeight() / 2;
velocity = new Vector2(0,0);
radius = RADIUS_RATIO * Math.min(viewport.getScreenWidth(), viewport.getScreenHeight());
startKick();
}
public void update(float delta, Viewport viewport) {
float elapsedSeconds = MathUtils.nanoToSec * (TimeUtils.nanoTime() - lastKick);
if (elapsedSeconds > KICK_INTERVAL) {
lastKick = TimeUtils.nanoTime();
startKick();
}
velocity.x -= delta * DRAG * velocity.x;
velocity.y -= delta * DRAG * velocity.y;
position.x += velocity.x * delta;
position.y += velocity.y * delta;
collision(radius,viewport);
}
public void collision(float radius, Viewport viewport) {
if (position.x + radius > viewport.getWorldWidth()) {
position.x = viewport.getWorldWidth() - radius;
velocity.x = -velocity.x;
}
if (position.x - radius < 0) {
position.x = radius;
velocity.x = -velocity.x;
}
if (position.y + radius > viewport.getScreenHeight()) {
position.y = viewport.getWorldHeight() - radius;
velocity.y = -velocity.y;
}
if (position.y - radius < 0) {
position.y = radius;
velocity.y = -velocity.y;
}
}
public void startKick() {
Random random = new Random();
float angle = random.nextFloat() * MathUtils.PI2;
velocity.x = START_KICK * MathUtils.cos(angle);
velocity.y = START_KICK * MathUtils.sin(angle);
}
public void render(ShapeRenderer renderer) {
renderer.setColor(Color.RED);
renderer.circle(position.x, position.y, radius);
}
}
Here is the Screen Class for Bouncing Ball
public class BallScreen extends ScreenAdapter {
private static final float WORLD_SIZE = 480f;
private static final String TAG = BallScreen.class.getSimpleName();
private BouncingBall ball;
private Viewport viewport;
private ShapeRenderer renderer;
#Override
public void show() {
Gdx.app.log(TAG, "Show");
viewport = new FitViewport(WORLD_SIZE, WORLD_SIZE);
renderer = new ShapeRenderer();
ball = new BouncingBall(viewport);
}
#Override
public void resize(int width, int height) {
Gdx.app.log(TAG, "resize" + width + " " + height);
viewport.update(width,height,true);
ball.init(viewport);
}
#Override
public void dispose() {
Gdx.app.log(TAG, "dispose");
renderer.dispose();
}
#Override
public void render(float delta) {
viewport.apply();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.setProjectionMatrix(viewport.getCamera().combined);
renderer.begin(ShapeType.Filled);
ball.update(delta, viewport);
ball.render(renderer);
renderer.end();
}
}
Problem is in this line :
radius = RADIUS_RATIO * Math.min(viewport.getScreenWidth(), viewport.getScreenHeight());
When you create FitViewPort and pass to BouncingBall, at that time viewport having only worldWidth and worldHeight that is what you set 480. At that time screenwidth and screenheight of viewport is zero so your radius initialise with zero value.
But After update() method if I call init() method :
viewport.update(width,height,true); // this method set value to screenwidth/height
when you call update method on viewport after that screenwidth and screenheight of viewport having some value according to what type of ViewPort you're using.
After update() if I call ball.init(viewport); then radius is not zero value so that ball is visible on screen.

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.

How to create an animated rectangle in java gui?

To be clear, I want to have a blue circle bouncing left to right which stops on click. This part works. But I also need to have a red rectangle bouncing up and down in the same gui which also stops on click. Each object should stop individually. However, two circles appear where one is moving and the other one is just still. Thanks in Advance! Help is appreciated.
/*
* This program creates an animation for a circle.
*/
package circleanimation;
import java.awt.*;
/*
* #author talhaiqbal18
*/
public class CircleAnimation
{
private int centerX, centerY, radius;
private Color color;
private int direction, speed;
private boolean filled;
public CircleAnimation(int x, int y, int r, Color c) {
centerX = x;
centerY = y;
radius = r;
color = c;
direction = 0;
speed = 0;
filled = false;
}
public void draw(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
if (filled) {
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.fillRect(200, 200, 200, 200); }
else {
g.fillRect(200, 200, 200, 200);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.setColor(oldColor); }
}
public void fill(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.fillRect(200, 200, 200, 200);
g.setColor(oldColor);
}
public boolean containsPoint(int x, int y) {
int xSquared = (x - centerX) * (x - centerX);
int ySquared = (y - centerY) * (y - centerY);
int radiusSquared = radius * radius;
return xSquared + ySquared - radiusSquared <= 0;
}
public void move(int xAmount, int yAmount) {
centerX = centerX + xAmount;
centerY = centerY + yAmount;
}
public int getRadius() {
return radius;
}
public int getX() {
return centerX;
}
public int getY() {
return centerY;
}
public void setSpeed(int s) {
speed = s;
}
public void setDirection(int d) {
direction = d % 360;
}
public void turn(int degrees) {
direction = (direction + degrees) % 360;
}
public void move() {
move((int)(speed * Math.cos(Math.toRadians(direction))),
(int)(speed * Math.sin(Math.toRadians(direction))));
}
public void setFilled(boolean b) {
filled = b;
}
}
/*
* This is the color panel class for the circle animation project.
*/
package circleanimation;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/*
* #author talhaiqbal18
*/
public class ColorPanel extends JPanel
{
private CircleAnimation circle, rectangle;
private javax.swing.Timer timer;
private CircleAnimation selectedCircle, selectedRectangle;
private int x, y;
public ColorPanel(Color backColor, int width, int height) {
setBackground(backColor);
setPreferredSize(new Dimension(width, height));
circle = new CircleAnimation(350, 300, 350, Color.blue);
circle.setDirection(180);
circle.setSpeed(6);
rectangle = new CircleAnimation(350, 300, 400, Color.red);
rectangle.setDirection(90);
rectangle.setSpeed(6);
timer = new javax.swing.Timer(1, new MoveListener());
timer.start();
addMouseListener(new PanelListener());
addMouseMotionListener(new PanelMotionListener());
addMouseMotionListener(new PanelMotionListener1());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
circle.fill(g);
rectangle.fill(g);
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
int x = circle.getX();
int radius = circle.getRadius();
int width = getWidth();
if (x - radius <= 0 || x + radius >= width) {
circle.turn(180);
}
circle.move();
repaint();
}
}
private class MoveListener1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
int x = rectangle.getX();
int radius = rectangle.getRadius();
int width = getWidth();
if (x - radius <= 0 || x + radius >= width) {
rectangle.turn(270);
}
rectangle.move();
repaint();
}
}
private class PanelListener extends MouseAdapter {
public void mousePressed(MouseEvent e)
{
x = e.getX();
y = e.getY();
if (circle.containsPoint(x, y))
selectedCircle = circle;
if (rectangle.containsPoint(x, y))
selectedRectangle = rectangle;
}
public void mouseReleased(MouseEvent e) {
//nothing
}
public void mouseClicked(MouseEvent e) {
if(timer.isRunning())
timer.stop();
else
timer.start();
}
}
private class PanelMotionListener extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
int newX = e.getX();
int newY = e.getY();
int dx = newX - x;
int dy = newY - y;
if (selectedCircle != null) {
selectedCircle.move(dx,dy);
x = newX;
y = newY;
repaint(); }
}
}
private class PanelMotionListener1 extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
int newX = e.getX();
int newY = e.getY();
int dx = newX - x;
int dy = newY - y;
if (selectedRectangle != null) {
selectedRectangle.move(dx,dy);
x = newX;
y = newY;
repaint(); }
}
}
}
/*
* This is the main method which will implement the actions of the previous classes.
*/
package circleanimation;
import java.awt.*;
import javax.swing.JFrame;
/*
* #author talhaiqbal18
*/
public class MainClass
{
public static void main(String[] args) throws Exception {
JFrame theGUI = new JFrame();
theGUI.setTitle("Circle Animation");
theGUI.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
ColorPanel panel = new ColorPanel(Color.white, 100, 100);
Container pane = theGUI.getContentPane();
pane.add(panel);
theGUI.setVisible(true);
}
}
You only register a timer for your circle, but not for your rectangle in the ColorPanel constructor

Wrong coordinates for different objects

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

Categories

Resources