Polygon position for collision detection won't update? or Collide? - java

I'm using polygons for a method of collision detection. I have a rock, the moves in a certain direction.
When I run the application, the polygon renders into a perfect rectangle where the rock is when it is started.
Yet, it doesn't move with the rock.
public Polygon box;
private int width;
public int height;
public float [] vertices;
public Rock (float x, float y, int width, int height) {
this.width = width;
this.height = height;
position = new Vector2(x, y);
velocity = new Vector2(20, 0);
vertices = new float[] {position.x, position.y, position.x+width, position.y, position.x+width, position.y+height,
position.x, position.y+height};
box = new Polygon ();
box.setOrigin(width/2, height/2);
}
public void RockMove (float delta) {
position.add(velocity.cpy().scl(delta));
box.setVertices(vertices);
box.setPosition(position.x, position.y);
}
sprite batch for rock
public void render (float delta) {
batch.begin();
batch.enableBlending();
batch.draw(rock, rock.GetX(), rock.GetY(), rock.GetWidth(), rock.GetHeight());
batch.disableBlending();
batch.end();
}
And this is some code from a render class
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.setColor(Color.RED);
shapeRenderer.polygon(Rock.vertices);
shapeRenderer.end();
Again, the polygon shows up perfectly, but doesn't move. I don't have any errors.
Edit: I defined the vertices again in the Rock Move method, and now they move with the rock.
public void RockMove (float delta) {
position.add(velocity.cpy().scl(delta));
box.setVertices(vertices);
box.setPosition(position.x, position.y);
vertices = new float[] {position.x, position.y, position.x+width,
position.y, position.x+width, position.y+height,
position.x, position.y+height};
}
But for some reason, the collision detection won't work.

Don't define vertices again in update instead of you should use transformedVertices of Polygon.
Polygon polygon=new Polygon();
float transformed[] = polygon.getTransformedVertices();
TransformedVertices is the vertices of the polygon after scaling, rotation, and positional translations have been applied.

Related

Create custom drawing tool with processing

I am currently in the process of coding a kind of drawing tool in Processing. I want to be able to draw a black line with the mouse, but have it fade away again. For this I first thought of working with a black ellipse that fades from black to white. This ellipse is then linked to the mouse pointer via mouseX and mouseY. Because I want each drawn ellipse to fade from black to white individually (to create the effect that the line fades again), I thought of working with objects. This works so far, but the fading does not work yet.
I want the ellipse at the mouse pointer to always be black and then only change to white once the mouse pointer has been moved further or drawn further... just like a fade...
Should I use an ArrayList for this? And say that a new object should be drawn at the MouseX and MouseY position per frame? Do I need PVector for this?
This is what I came up for this so far:
float counter;
PGraphics pg;
Brush myBrush;
void setup() {
size(600, 600);
pg = createGraphics(width, height);
}
void draw() {
//background(255);
color from = color(0);
color to = color(255);
color faded = lerpColor(from, to, counter);
myBrush = new Brush(faded, mouseX, mouseY);
myBrush.display();
}
class Brush {
color tempC;
float xpos;
float ypos;
color c;
Brush(color tempC, float tempXpos, float tempYpos) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
}
void display() {
noStroke();
fill(c);
ellipse(xpos, ypos, 50, 50);
counter = counter + 0.01;
}
}
The issue you're struggling with here is that you can only know how to fade the line once the line has been drawn, but you draw it while the user move the mouse.
To deal with this issue, I would suggest to store every information needed to draw the line in an object, and update it as the user is drawing. As you guessed, you could totally use an ArrayList to achieve this.
I modified your code quite heavily to simplify my own life, and I commented the result so it would be easier for you to re-cast it into your own project on your own terms.
I used objects to keep everything tidy. The logic here goes as follow: The Canvas object contains the drawing. It's made of Line objects, which are themselves made of Dots.
Here's the commented code:
Canvas canvas;
void setup() {
size(600, 600);
canvas = new Canvas();
}
void draw() {
// instead of drawing only once, we're going to save every line the user draw in teh canvas object
background(255);
// the canvas object has to calculate stuff, then display itself
canvas.Update();
canvas.Display();
}
// setting up the mousePressed and mouseReleased events so the canvas object "knows"
void mousePressed() {
canvas.mouseDown = true;
}
void mouseReleased() {
canvas.mouseReleased = true;
canvas.mouseDown = false;
}
class Canvas {
boolean mouseDown;
boolean mouseReleased = true;
ArrayList<Line> lines = new ArrayList<Line>(); // every line will be stored in this list
Brush brush; // the brush object can be modified with different sizes or colors
Canvas() {
// here i use a default brush, but you can experiment different colors or sizes
brush = new Brush(color(0, 200, 0), color(0), color(255), 50);
}
void Update() {
brush.highlight = mouseDown; // so the user has visual feedback while drawing
if (mouseDown) {
if (mouseReleased) { // if this is a "new" line, add a line object to store it
lines.add(new Line(brush.colorFrom, brush.colorTo));
mouseReleased = false;
}
// add a dot at the mouse's current position, then update the fading
lines.get(lines.size()-1).Add(new Dot(mouseX, mouseY, brush.diameter, brush.colorFrom));
lines.get(lines.size()-1).ApplyFade();
}
}
void Display() {
// for every Line, draw every Dot... then don't forget to display the brush!
for (Line l : lines) {
for (Dot d : l.dots) {
d.Display();
}
}
brush.Display();
}
}
// A line is a bunch of dots and two colord (for the fade effect)
class Line {
ArrayList<Dot> dots = new ArrayList<Dot>();
color colorFrom, colorTo;
Line(color colorFrom, color colorTo) {
this.colorFrom = colorFrom;
this.colorTo = colorTo;
}
void Add(Dot d) {
dots.add(d);
}
// This method calculate how many dots there are in the line to better distribute the shades of the fade
void ApplyFade() {
for (int i=0; i<dots.size(); i++) {
Dot d = dots.get(i);
d.c = lerpColor(colorFrom, colorTo, (float) i/dots.size());
}
}
}
// a Dot has a size, a position and a color
class Dot {
float xpos;
float ypos;
float diameter;
color c;
Dot(float xpos, float ypos, float diameter, color c) {
this.xpos = xpos;
this.ypos = ypos;
this.diameter = diameter;
this.c = c;
}
void Display() {
noStroke();
fill(c);
ellipse(xpos, ypos, diameter, diameter);
}
}
// this class is overdesigned so in the future you can change the brush's characteristics like the fade'S colors or simply it's size
class Brush {
boolean highlight;
float diameter, xpos, ypos;
color circleColor, colorFrom, colorTo;
Brush(color circleColor, color colorFrom, color colorTo, float diameter) {
this.circleColor = circleColor;
this.colorFrom = colorFrom;
this.colorTo = colorTo;
this.diameter = diameter;
}
void Display() {
stroke(circleColor);
strokeWeight(5);
noFill();
ellipse(mouseX, mouseY, diameter, diameter);
if (highlight) { // if the mouse's button is down, give visual feedback about the brush
stroke(0);
strokeWeight(4);
ellipse(mouseX, mouseY, diameter, diameter);
stroke(255);
strokeWeight(3);
ellipse(mouseX, mouseY, diameter, diameter);
}
}
}
Hope this helps. I'll be around if you have questions about the code. Have fun!
Here is a version with an ArrayList and Object... The problem here is that all ellipse objects fade away at the same time... I would like to achieve that each ellipse is first drawn black and then after time X becomes white... Like a fingerprint on a sensor for example... A lot of pressure: black, little pressure (or no pressure): fade to white... Later on I want to draw everything on a PGraphics layer – therefore there is alyready this variable...
float counter;
PGraphics pg;
ArrayList<PVector> positionsList;
Brush myBrush;
void setup() {
size(600, 600);
positionsList = new ArrayList<PVector>();
pg = createGraphics(width, height);
}
void draw() {
background(255);
color from = color(0);
color to = color(255);
color faded = lerpColor(from, to, counter);
for (PVector p : positionsList) {
myBrush = new Brush(faded, p.x, p.y);
myBrush.display();
}
positionsList.add(new PVector(mouseX, mouseY));
counter = counter + 0.01;
}
class Brush {
color tempC;
float xpos;
float ypos;
color c;
Brush(color tempC, float tempXpos, float tempYpos) {
c = tempC;
xpos = tempXpos;
ypos = tempYpos;
}
void display() {
noStroke();
fill(c);
ellipse(xpos, ypos, 50, 50);
}
}

LibGDX float with camera position causing black lines with Tiled map

I am creating a top-down shooter game, and whenever I move the camera, or zoom, black likes appear like a grid
I am using Tiled to create the map, and I have the camera following my centered box2d body. I have found that making the camera position equal the position of the box2d body with an int cast results in the black lines disappearing like this:
The problem though, is that because I have the game scaled down, the player will move for a second or two and then when the player reaches the next whole number on either axis, the camera snaps to the player, which is not what I want for the game as it's jarring. The player's movement is granular, but, while rounded, the camera's is not. I do not know if this is a problem with my tile sheet or if it's something I can fix by altering some code. I have tried all different kinds of combinations of padding, and values of spacing and margins. So ultimately, how can I have the camera match the player's position smoothly and not cause the black lines? I'd greatly appreciate any help or recommendations. Thank you in advance!
Where I am type casting the player's float position to an int in game class:
public void cameraUpdate(float delta) {
//timeStep = 60 times a second, velocity iterations = 6, position iterations = 2
world.step(1/60f, 6, 2); //tells game how many times per second for Box2d to make its calculations
cam.position.x = (int)playerOne.b2body.getPosition().x;
cam.position.y = (int)playerOne.b2body.getPosition().y;
cam.update();
}
Majority of player class:
public class PlayerOne extends Sprite implements Disposable{
public World world; // world player will live in
public Body b2body; //creates body for player
private BodyDef bdef = new BodyDef();
private float speed = 1f;
private boolean running;
TextureAtlas textureAtlas;
Sprite sprite;
TextureRegion textureRegion;
private Sound runningSound;
public PlayerOne(World world) {
this.world = world;
definePlayer();
textureAtlas = new TextureAtlas(Gdx.files.internal("sprites/TDPlayer.atlas"));
textureRegion = textureAtlas.findRegion("TDPlayer");
sprite =new Sprite(new Texture("sprites/TDPlayer.png"));
sprite.setOrigin((sprite.getWidth() / 2) / DunGun.PPM, (float) ((sprite.getHeight() / 2) / DunGun.PPM - .08));
runningSound = Gdx.audio.newSound(Gdx.files.internal("sound effects/running.mp3"));
}
public void definePlayer() {
//define player body
bdef.position.set(750 / DunGun.PPM, 400 / DunGun.PPM);
bdef.type = BodyDef.BodyType.DynamicBody;
//create body in the world
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
CircleShape shape = new CircleShape();
shape.setRadius(12 / DunGun.PPM);
fdef.shape = shape;
b2body.createFixture(fdef);
}
public void renderSprite(SpriteBatch batch) {
float posX = b2body.getPosition().x;
float posY = b2body.getPosition().y;
float posX2 = (float) (posX - .14);
float posY2 = (float) (posY - .1);
sprite.setSize(32 / DunGun.PPM, 32 / DunGun.PPM);
sprite.setPosition(posX2, posY2);
float mouseX = Level1.mouse_position.x; //grabs cam.unproject x vector value
float mouseY = Level1.mouse_position.y; //grabs cam.unproject y vector value
float angle = MathUtils.atan2(mouseY - getY(), mouseX - getX()) * MathUtils.radDeg; //find the distance between mouse and player
angle = angle - 90; //makes it a full 360 degrees
if (angle < 0) {
angle += 360 ;
}
float angle2 = MathUtils.atan2(mouseY - getY(), mouseX - getX()); //get distance between mouse and player in radians
b2body.setTransform(b2body.getPosition().x, b2body.getPosition().y, angle2); //sets the position of the body to the position of the body and implements rotation
sprite.setRotation(angle); //rotates sprite
sprite.draw(batch); //draws sprite
}
public void handleInput(float delta) {
setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2 + (5 / DunGun.PPM));
this.b2body.setLinearVelocity(0, 0);
if(Gdx.input.isKeyPressed(Input.Keys.W)){
this.b2body.setLinearVelocity(0f, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.S)){
this.b2body.setLinearVelocity(0f, -speed);
}if(Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, 0f);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, speed);
}if(Gdx.input.isKeyPressed(Input.Keys.W) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, speed);
}
if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.A)){
this.b2body.setLinearVelocity(-speed, -speed );
}if(Gdx.input.isKeyPressed(Input.Keys.S) && Gdx.input.isKeyPressed(Input.Keys.D)){
this.b2body.setLinearVelocity(speed, -speed);
}
Where I declare the pixels per meter scale:
public class DunGun extends Game{
public SpriteBatch batch;
//Virtual Screen size and Box2D Scale(Pixels Per Meter)
public static final int V_WIDTH = 1500;
public static final int V_HEIGHT = 800;
public static final float PPM = 100; //Pixels Per Meter
Game render and resize methods:
#Override
public void render(float delta) {
cameraUpdate(delta);
playerOne.handleInput(delta);
//clears screen
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
cam.zoom -= .01;
}
if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) {
cam.zoom += .01;
}
mapRenderer.render();
b2dr.render(world, cam.combined); //renders the Box2d world
mapRenderer.setView(cam);
//render our game map
//mapRenderer.render(); // renders map
//mapRenderer.render(layerBackround); //renders layer in Tiled that p1 covers
game.batch.setProjectionMatrix(cam.combined); //keeps player sprite from doing weird out of sync movement
mouse_position.set(Gdx.input.getX(), Gdx.input.getY(), 0);
cam.unproject(mouse_position); //gets mouse coordinates within viewport
game.batch.begin(); //starts sprite spriteBatch
playerOne.renderSprite(game.batch);
game.batch.end(); //starts sprite spriteBatch
//mapRenderer.render(layerAfterBackground); //renders layer of Tiled that hides p1
}
#Override
public void resize(int width, int height) {
viewport.update(width, height, true); //updates the viewport camera
}
I solved it by fiddling around with the padding of the tilesets in GDX Texture Packer. I added 5 pixels of padding around the 32x32 tiles. I set the margins to 2, and spacing to 4 in Tiled. I had tried a lot of different combinations of padding/spacing/margins that didn't work which made me think it was a coding problem, but those settings worked, and I didn't have to round the floats.

LibGdx Box2d collison not matching up with sprite

I am making a game as a project for a college class. when my main character (the tree) hits the ground, it stops short of the ground
screenshot 1
and when the player lands on the little platform that gap is even bigger
screenshot 2
my code for creating the body of the character and and ground is this
public static Body createBody(int x, int y, float width, float height, boolean isStatic){
Body body;
BodyDef def = new BodyDef();
if(isStatic){
def.type = BodyDef.BodyType.StaticBody;
}
else {
def.type = BodyDef.BodyType.DynamicBody;
}
def.position.set(x / PPM , y / PPM);
// returns a World object
body = GlobalWorld.getInstance().createBody(def);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width / 2 / PPM, height / 2 / PPM);
body.createFixture(shape, 1.0f);
shape.dispose();
return body;
}
The code for the ground is in it's own class
public class Material {
private Texture image;
private Body body;
private Sprite sprite;
public Material(Texture t, int x, int y, int w, int h){
image = t;
sprite = new Sprite(t);
body = BoxBuilder.createBody(x, y, w, h, true);
body.setUserData("Ground");
}
public void draw(){
// returns a SpriteBatch
SpriteBatch batch = GlobalBatch.getInstance();
sprite.setPosition(body.getPosition().x * PPM, body.getPosition().y * PPM);
batch.begin();
sprite.draw(batch);
batch.end();
}
public void dispose(){
image.dispose();
}
}
the code for drawing the ground
public void draw(){
for(Material m : worldObjects){
m.draw();
}
}
my code for drawing the character
public void create(){
// do stuff
// global vars
body = createBody(0, 480, 313, 260, false);
texture = new Texture("tree.PNG");
sprite = new Sprite(texture);
// do stuff
}
public void render(){
// do stuff
sprite.setPosition(body.getPosition().x*PPM, body.getPosition().y*PPM);
batch.begin()
sprite.draw(batch)
batch.end()
// do stuff
}
and PPM(Pixel per Meter) is
public static final float PPM = 32;
I don't know what is the problem here, I want the character to land on the ground, not land above it. So if someone could tell me what's causing this or point me to a good tutorial for learning more about box2d I'd appreciate it.
When we create body with PolygonShape then body is at the center of that Polygon so when draw with body position it starts drawing from center of PolygonShape so we need to draw at left bottom corner.
In Material class
replace
sprite.setPosition(body.getPosition().x * PPM, body.getPosition().y * PPM);
with
sprite.setPosition(body.getPosition().x*PPM-sprite.getWidth()/2,body.getPosition().y-sprite.getHeight()/2);
sprite.setRotation(body.getAngle()*MathUtils.radDeg);
And for Character draw also change
sprite.setPosition(body.getPosition().x*PPM, body.getPosition().y*PPM);
with
sprite.setPosition(body.getPosition().x*PPM-sprite.getWidth()/2, body.getPosition().y*PPM-sprite.getHeight()/2);
sprite.setRotation(body.getAngle()*MathUtils.radDeg);
As I see in your code you're not setting size of Sprite in Material class as well as for Character so set width and height.
In Material Class
sprite = new Sprite(t);
sprite.setSize(w,h);
And for Character
body = createBody(0, 480, 313, 260, false);
texture = new Texture("tree.PNG");
sprite = new Sprite(texture);
sprite.setSize(313,260);

Java 2D Game rotate to mouse glitch?

I am making a game in Java (No Libraries).
It's a 2D top-down game where the player can walk and is faced towards the mouse cursor.
public Player(int x, int y, int health, int tileId) {
super(x, y, health);
tile = new Tile(tileId, false);
mouseInput = new MouseHandler(screen);
}
public void tick() { // Executed by game tick.
// x = playerX and y = playerY
int cursorX = mouseInput.getMousePos()[0];
int cursorY = mouseInput.getMousePos()[1];
float X = cursorX - x;
float Y = cursorY - y;
rotation = Math.atan2(Y, X);
}
It looks good as long the player is at (0,0)
If the player moves and the mouse coordinates become negative it begins to show strange behaviour (Look at video below)
Youtube: https://www.youtube.com/watch?v=M6ZHCrWvt3Y
The rotation of the sprite is done in another class 'Screen.java'
By using:
if (rotation < 360)
rotation++
else
rotation = 0
I verified that the rotation is working correctly.
EDIT:
public BufferedImage rotate(BufferedImage img, double degree) {
AffineTransform tx = new AffineTransform();
tx.rotate(degree, 4, 4);
AffineTransformOp op = new AffineTransformOp(tx,AffineTransformOp.TYPE_BILINEAR);
BufferedImage image = op.filter(img,null);
return image;
}
Okay i fixed it.
The problem was the game scale i am making an 2d game and set the width, height and the scale.
But i didn't divide the mouseX and mouseY by the scale.
public void mouseMoved(MouseEvent e) {
mouseX = e.getX() / game.getScale();
mouseY = e.getY() / game.getScale();
}
I found the problem by accident when messing with the gamescale.

libgdx vector2: shooting ball at an angle

I'm using Libgdx: I have a sprite that is supposed to shoot a ball when touching the screen. The touchPoint should define the direction of the ball. I can't figure out how to rotate and shoot in the correct direction.
public void update(float deltaTime) {
double angle = Math.toRadians(Math.atan2(position.y, position.x));
position.x = (float)Math.cos(angle) * position.x - (float)Math.sin(angle) * position.y;
position.y = (float)Math.sin(angle) * position.x + (float)Math.cos(angle) * position.y;
}
The ball takes off, but shoots in the wrong direction. Is there a way using Vector2.rotate function instead?
I'd do something like this, assuming you are shooting the ball from its current position (or any known position really) toward the touched position:
public class Snippet extends ApplicationAdapter {
ShapeRenderer renderer;
OrthographicCamera camera;
Ball ball = new Ball();
#Override
public void create () {
renderer = new ShapeRenderer();
camera = new OrthographicCamera();
camera.setToOrtho(false);
}
#Override
public void render () {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
ball.update(Gdx.graphics.getDeltaTime());
renderer.setProjectionMatrix(camera.combined);
renderer.begin(ShapeType.Line);
renderer.setColor(1.0f, 1.0f, 1.0f, 1.0f);
renderer.circle(ball.position.x, ball.position.y, ball.radius);
// Show the travel path of the ball if we were to click at the current location.
if (Gdx.app.getType() == ApplicationType.Desktop || Gdx.app.getType() == ApplicationType.WebGL) {
renderer.setColor(0.2f, 0.2f, 0.2f, 1.0f);
renderer.line(ball.position.x, ball.position.y, Gdx.input.getX(), Gdx.graphics.getHeight()- Gdx.input.getY());
}
renderer.end();
if (Gdx.input.justTouched()) {
// Invert the the y to accommodate difference in coordinate systems
ball.shootToward(Gdx.input.getX(), Gdx.graphics.getHeight()- Gdx.input.getY());
}
}
class Ball {
public float speedMax = 350;
public float radius = 10;
public Vector2 position = new Vector2();
public Vector2 velocity = new Vector2();
/** Shoot the ball toward the designated position */
public void shootToward(float targetX, float targetY) {
/*
* Get the normalized direction vector from our position to the target. Then scale that value to our desired speed. In
* this particular example, we are using the distance of the target from the current position to determine how fast we
* will shoot the ball, and limiting to a maximum speed. We will apply velocity in the update method.
*/
velocity.set(targetX - position.x, targetY - position.y).nor().scl(Math.min(position.dst(targetX, targetY), speedMax));
}
public void update(float deltaTime) {
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
velocity.scl(1 - (0.98f * deltaTime)); // Linear dampening, otherwise the ball will keep going at the original velocity forever
}
}
public static void main(String[] args) {
new LwjglApplication(new Snippet2());
}
}

Categories

Resources