Problem with changing variables of objects - java

my problem is that when one ball object collides with the left, right or top of the screen, or collided with either of the bricks it will invert the velocity of all the balls for example if ball 1 hits the left wall it will bounce off in the opposite X direction. However, ball 2 will also do the same even when it doesn't collide with anything (the same thing happens to ball 1 when ball 2 hits something).
I am using the Processing development environment. however, this uses Java, specifically the PApplet class
This is my method to move the balls:
void moveBalls(){
PVector ballPos;
for(balls b : ballsCollection){
ballPos = b.getPos();
if(b.isMoving()) {
//make the ball bounce off the walls
if(ballPos.y > height - blockSize){ //bottom
if(ballsInMotion == ballsCollection.size()){
ballPos.y = height - ballSize/2 - blockSize - 3;
ballStartX = ballPos.x;
ballStartY = height - blockSize - ballSize - ballSize/2;
b.invertMoving();
ballsInMotion -=1;
println("FirstBall down" + ballPos);
} else {
b.invertMoving();
ballsInMotion -=1;
PVector p = new PVector(ballStartX,ballStartY);
b.setPos(p);
println("Next ball Down new P: " + p);
}
if(ballsInMotion == 0){
setUpNextRound = true;
}
}
if (ballPos.y < ballSize + blockSize){ //top
b.invertV("y");
ballPos.y = ballSize+blockSize;
println("ball " + b.getIndex() + " hit Top");
}
if (ballPos.x > width - ballSize/2){ //right
b.invertV("x");
ballPos.x = 2*width-ballSize-ballPos.x;
println("ball " + b.getIndex() + " hit right");
}
if (ballPos.x < ballSize/2){ //left
b.invertV("x");
ballPos.x = ballSize-ballPos.x;
println("ball " + b.getIndex() + " hit left");
}
for(blocks block : blocksCollection){
int blockHealth = block.getBlockHealth();
int blockX = block.getX();
int blockY = block.getY();
boolean hit = false;
if(blockHealth > 0){
// Bottom of the block Top of the Block
if(!hit && (blockBallCollision(blockX+blockSize/2, blockY+blockSize, blockSize-blockCournerSize, 0, ballPos.x-b.getV().x, ballPos.y-b.getV().y, 2*(ballSize)) || blockBallCollision(blockX+blockSize/2, blockY, blockSize-blockCournerSize, 0, ballPos.x-b.getV().x, ballPos.y-b.getV().y, 2*(ballSize)))) {
println("Block Collision Top/Bottom: " + block.getIndex() + " by Ball: " + b.getIndex());
b.invertV("y");
block.blockHit();
hit = true;
// Left of the block Right of the Block
} else if ( !hit && (blockBallCollision(blockX, blockY+blockSize/2, 0, blockSize-blockCournerSize, ballPos.x-b.getV().x, ballPos.y-b.getV().y, 2*(ballSize)) || blockBallCollision(blockX+blockSize, blockY+blockSize/2, 0, blockSize-blockCournerSize, ballPos.x-b.getV().x, ballPos.y-b.getV().y, 2*(ballSize)))){
println("Block Collision Left/Right: " + block.getIndex() + " by Ball: " + b.getIndex());
b.invertV("x");
block.blockHit();
hit = true;
}
}
}
b.movePosV();
drawBalls();
}
}
}
The ball object is stored:
public class balls{
private int index;
private PVector b = new PVector();
private PVector bV = new PVector();
private boolean moving, needMoving;
public balls(int Index, float X, float Y, boolean m, PVector ballV){
index = Index;
b.x = X;
b.y = Y;
moving = m;
bV = ballV;
}
public void movePosV(){
b.sub(bV);
}
public void invertV(String xy){
if(xy.equals("x")){
bV.x = -bV.x;
} else {
bV.y = -bV.y;
}
}
public void setPos(PVector newB){
b = newB;
}
public void setV(PVector newV){
bV = newV;
}
public boolean getNeedMoving(){
return needMoving;
}
public PVector getV(){
return bV;
}
public PVector getPos(){
return b;
}
public int getIndex(){
return index;
}
public boolean isMoving(){
return moving;
}
public void invertMoving(){
moving = !moving;
}
public void invertNeedMoving(){
needMoving = !needMoving;
}
}

Related

How to stop the normal force from being too small on a 2D rigidbody? (Java 2D)

I am trying to create a 2D game engine in Java with LWJGL 3. For now the objects are only rectangles with box colliders. For the collision detection I change the edge of the rectangles in to lines with the y = ax + b structure. One of the rectangles has a rigidbody component, that gives it the ability to move and interact with environment. The idea for now is to give the rigidbody a force at the start, gravity turned off, no friction, and a perfect bounce (bounciness=1). It all works very well, till it hits a rectangle with no vertical and horizontal edges. I found out that if the non-rigidbody objects are rotated by an angle other than 90 or 180 degrees the normal force is wrong (too small), how wrong depends on the rotation. The rotation of the rigidbody doesn't contribute to the problem.
Vector2 rotSurface = new Vector2(-collision.surface.ToVector().y, collision.surface.ToVector().x).getNormalized();
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
rb.force = rb.force.add(normalForce).multiplyBy(1f - rb.friction).add(normalForce.multiplyBy(rb.bounciness));
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
System.out.println("===");
Am I doing something wrong here with calculating the new rigidbody force or the normal force itself? If you need more information to help me solve this problem please ask.
Classes that I use in the code above:
public class Collision {
Collider collider;
ArrayList<Vector2> contactPoints = new ArrayList<Vector2>();
Vector2 center = Vector2.zero;
Line surface;
public Collision(Collider collider, ArrayList<Vector2> contactPoints, Line surface) {
this.collider = collider;
this.contactPoints = contactPoints;
for(int i = 0; i < contactPoints.size(); i++) {
center = contactPoints.get(i).add(center).divideBy(2);
}
this.surface = surface;
}
}
class Line {
Vector2 begin, eind;
public float rc = 0;
public float b = 0;
public float x, y;
public boolean vertical = false;
public boolean horizontal = false;
public Line(Vector2 begin, Vector2 eind) {
this.begin = begin;
this.eind = eind;
if(begin.y == eind.y) {
this.y = begin.y;
this.horizontal = true;
}
else if(begin.x == eind.x){
this.x = begin.x;
this.vertical = true;
} else {
this.rc = (eind.y - begin.y) / (eind.x - begin.x);
this.b = GetB(rc, begin);
}
}
public float GetB(float rc, Vector2 punt) {
return punt.y - (rc * punt.x);
}
public Vector2 GetIntersection(Line l2) {
float x_ = rc - l2.rc;
if(vertical) {
x_ = x;
if(l2.horizontal) {
return new Vector2(x, l2.y);
}
else if(!l2.vertical){
//System.out.println("gert");
return new Vector2(x, l2.rc * x + l2.b);
}
} else if(horizontal) {
if(l2.vertical) {
return new Vector2(l2.x, y);
} else if(!l2.horizontal) {
return new Vector2((y-l2.b) / l2.rc, y);
}
} else {
if(l2.vertical) {
return new Vector2(l2.x, rc * l2.x + b);
} else if(l2.horizontal) {
return new Vector2((l2.y - b) / rc, l2.y);
}
}
if(x_ == 0) {
return null;
}
float getal = l2.b - b;
x_ = getal / x_;
float y_ = rc * x_ + b;
return new Vector2(x_, y_);
}
public Vector2 ToVector() {
return eind.substract(begin);
}
public float GetDisTo(Vector2 point) {
Vector2 point1 = begin.add(eind).divideBy(2);
return (float) Math.sqrt(Math.pow(point1.x - point.x, 2) + Math.pow(point1.y - point.y, 2));
}
public boolean Overlaps(Line line) {
if(horizontal && y == line.y) {
if(((line.begin.x > begin.x && line.begin.x < eind.x) || (line.eind.x > begin.x && line.eind.x < eind.x)) ||
((begin.x > line.begin.x && begin.x < line.eind.x) || (line.eind.x > line.begin.x && eind.x < line.eind.x)))
return true;
} else if(vertical && x == line.x) {
//return true;
}
return false;
}
}
class Vector2 {
float x, y;
public static Vector2 zero = new Vector2(0, 0);
public Vector2(float x, float y) {
this.x = x;
this.y = y;
}
public Vector2 multiplyBy(Vector2 vector) {
return new Vector2(x * vector.x, y * vector.y);
}
public Vector2 multiplyBy(float getal) {
return new Vector2(x * getal, y * getal);
}
public Vector2 divideBy(Vector2 vector) {
return new Vector2(x / vector.x, y / vector.y);
}
public Vector2 divideBy(float getal) {
return new Vector2(x / getal, y / getal);
}
public Vector2 add(Vector2 vector) {
return new Vector2(x + vector.x, y + vector.y);
}
public Vector2 substract(Vector2 vector) {
return new Vector2(x - vector.x, y - vector.y);
}
public float getMagnitude() {
return (float)Math.sqrt(x*x + y*y);
}
public Vector2 getNormalized() {
return divideBy(getMagnitude());
}
}
Fixed it by using a sinus.
I replaced
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
with
Vector2 normalForce = rotSurface.multiplyBy((float)Math.sin(Math.toRadians((double) (90f - Physics.Angle(rotSurface, force)))) * force.getMagnitude());

Can't find the NullPointerException Error

I'm trying to build a Snake Game, where the snake is eating square orbs.
Before, the program was running perfectly, but when I ran it a couple of days ago, it yelled at me for something about a NullPointerException. I tried looking for what caused it, and it was in my Snake class.
Here is the code for the main class:
Snake s;
Score score;
//Menu m;
int sc1 = 20;
PVector food;
void setup() {
size(700, 700);
//m = new menu;
//m.show();
s = new Snake();
score = new Score();
//m.startGame();
frameRate(10);
}
void pickLocation() {
int cols = width/sc1;
int rows = height/sc1;
food = new PVector(floor(random(cols-20)), floor(random(rows-20)));
food.mult(sc1);
}
void draw() {
background(51);
if (s.eat(food)) {
pickLocation();
score.addPoints(10);
}
pickLocation();
score.show();
s.update();
s.show();
s.death();
if (s.dead == true) {
score.highScores();
}
if (score.totalScore != s.i/10) {
score.totalScore = s.i * 10;
}
if (s.dead && score.totalScore < score.highScore) {
score.totalScore = 0;
}
fill(255, 0, 100);
rect(food.x, food.y, sc1, sc1);
}
void keyPressed() {
if (keyCode == UP) {
s.dir(0, -1);
} else if (keyCode == DOWN) {
s.dir(0, 1);
} else if (keyCode == RIGHT) {
s.dir(1, 0);
} else if (keyCode == LEFT) {
s.dir(-1, 0);
}
}
The menu I commented out right now.
The Score class:
class Score {
int totalScore = 0; //will add the total score to the
int highScore; //will hold the user's high score in it.
int tempScore; //will hold the user's score after the snake dies.
Score() {
}
//this method is used when the snake eats the
//food. Eating the food will give 10 points to it.
void addPoints(int x) {
totalScore = totalScore + x;
}
//this method will calculate to see if the user
//has a new high score, only if the snake has
//officially died.
void highScores() {
if (totalScore > highScore) {
text("new highscore!", height/2, width/2);
highScore = totalScore;
totalScore = 0;
}
}
void show() {
text("Score: " + totalScore, 20, 20);
text("High Score: " + highScore, 20, 40);
}
}
And finally, my Snake class, where the problem is located at:
class Snake {
float x, y;
float xSpeed = 1;
float ySpeed = 0;
int total = 0;
ArrayList<PVector> tail = new ArrayList<PVector>();
boolean dead = false;
int i = 0;
Snake() {
}
boolean eat (PVector pos) {
float d = dist(x, y, pos.x, pos.y);
if (d < 1) {
total++;
return true;
} else {
return false;
}
}
void dir(float x, float y) {
xSpeed = x;
ySpeed = y;
}
void death() {
for (i = 0; i < tail.size(); i++) {
PVector pos = tail.get(i);
float d = dist(x, y, pos.x, pos.y);
if (d < 1) {
println("starting over");
total = 0;
tail.clear();
dead = true;
} else {
dead = false;
}
}
}
void update() {
if (total > 0) {
if (total == tail.size() && !tail.isEmpty()) {
tail.remove(0);
}
tail.add(new PVector(x, y));
}
x = x + xSpeed * sc1;
y = y + ySpeed * sc1;
x = constrain(x, 0, width-sc1);
y = constrain(y, 0, height-sc1);
}
void show() {
fill(0, 255, 0);
for (PVector v : tail) {
rect(v.x, v.y, sc1, sc1);
}
rect(x, y, sc1, sc1);
//rect(x, y, w, h);
}
}
My question is, is there something who can recognize the error and what should I do to fix such an error, please.
You need to get into the habit of debugging your code to understand exactly what's going on. You know that this line is throwing the NPE:
float d = dist(x, y, pos.x, pos.y);
So next, you need to understand the values of every variable on that line. You could just print them out:
boolean eat (PVector pos) {
println("x: " + x);
println("y: " + y);
println("pos: " + pos);
float d = dist(x, y, pos.x, pos.y);
If you do this, you'll see this output:
x: 0.0
y: 0.0
pos: null
This tells you that your pos variable is null, which is what's causing your NullPointerException.
Now you can trace backwards through your code to understand why the eat() function is being given a null argument.
In the future, please narrow your problem down to a MCVE instead of posting your whole program.

Cannot get sprite to collide with map images (java)

I am creating a 2D game which the zombie moves with WASD keys and is supposed to collide with the walls and not enter them, as well as collide with the brains and removes them. Every type of code I have used does not create collision. I am using a zombie sprite sheet i found on google as well as 2 backgroundless images for walls and brains.
After I figure out collision, I then then to implement a autorun sequence to where it bounces around like a screensaver and does the same thing just automatically until all brains are collected.
The EZ is just a library that is utilized by UH Manoa, that can be found here: EZ Graphics
Main
import java.awt.Color;
import java.io.FileReader;
import java.util.Scanner;
public class ZombieMain {
static EZImage[] walls = new EZImage[500];
static EZImage[] sideWalls = new EZImage[500];
static EZImage[] brains = new EZImage[50];
static int wallsCount = 0;
static int sideWallsCount = 0;
static int brainsCount = 0;
/*public static void addWall(EZImage wall) {
walls[wallsCount] = wall;
wallsCount++;
}
public static void addCoin(EZImage brain) {
brains[brainsCount] = brain;
brainsCount++;
}*/
/*public static void CollisingCoin(EZImage me) {
int x = me.getXCenter();
int y = me.getYCenter();
for (int i = 0; i < brainsCount; i++) {
if ((brains[i].isPointInElement(me.getXCenter() - 30, me.getYCenter() - 30))
|| (brains[i].isPointInElement(me.getXCenter() + 30, me.getYCenter() - 30))
|| (brains[i].isPointInElement(me.getXCenter() - 30, me.getYCenter() + 30))
|| (brains[i].isPointInElement(me.getXCenter() + 30, me.getYCenter() + 30))) {
brains[i].translateTo(-20, -20);
System.out.println("You ate a brain!");
}
}
}*/
public static void main(String[] args) throws java.io.IOException {
//initialize scanner
Scanner fScanner = new Scanner(new FileReader("boundaries.txt"));
int w = fScanner.nextInt();
int h = fScanner.nextInt();
String inputText = fScanner.nextLine();
//create backdrop
EZ.initialize(w*33,h*32);
EZ.setBackgroundColor(new Color(0, 0,0));
Zombie me = new Zombie("zombieSheet.png", 650, 450, 65, 63, 10);
//set reading parameters and establish results of case readings
int row = 0;
while(fScanner.hasNext()) {
inputText = fScanner.nextLine();
for (int column = 0; column < inputText.length(); column++){
char ch = inputText.charAt(column);
switch(ch){
case 'W':
walls[wallsCount] = EZ.addImage("barbwire.jpg", column*32, row*32);
wallsCount++;
break;
case 'M':
sideWalls[wallsCount] = EZ.addImage("barb.jpg", column*32, row*32);
wallsCount++;
break;
case 'B':
brains[brainsCount] = EZ.addImage("brains.png", column*32, row*32);
brainsCount++;
break;
default:
// Do nothing
break;
}
//printed count of walls, side walls, and brains
System.out.println("W = " + wallsCount);
System.out.println("M = " + sideWallsCount);
System.out.println("B = " + brainsCount);
}
row++;
}
fScanner.close();
while (true) {
// check if going to collide with wall
// we want to check this before we actually move
// otherwise, we get "stuck" in a situation where we can't move
// if no collision, we can move
/*if (EZInteraction.isKeyDown('a')) {
if (!isCollisingWall(me, -2, 0)) {
me.translateBy(-2, 0);
}
} else if (EZInteraction.isKeyDown('d')) {
if (!isCollisingWall(me, 2, 0)) {
me.translateBy(2, 0);
}
} else if (EZInteraction.isKeyDown('w')) {
if (!isCollisingWall(me, 0, -2)) {
me.translateBy(0, -2);
}
} else if (EZInteraction.isKeyDown('s')) {
if (!isCollisingWall(me, 0, 2)) {
me.translateBy(0, 2);
}
}*/
me.go();
EZ.refreshScreen();
}
}
}
Sprite
public class Zombie {
EZImage zombieSheet;
int x = 0; // Position of Sprite
int y = 0;
int zombieWidth; // Width of each sprite
int zombieHeight; // Height of each sprite
int direction = 0; // Direction character is walking in
int walkSequence = 0; // Walk sequence counter
int cycleSteps; // Number of steps before cycling to next animation step
int counter = 0; // Cycle counter
Zombie(String imgFile, int startX, int startY, int width, int height, int steps) {
x = startX; // position of the sprite character on the screen
y = startY;
zombieWidth = width; // Width of the sprite character
zombieHeight = height; // Height of the sprite character
cycleSteps = steps; // How many pixel movement steps to move before changing the sprite graphic
zombieSheet = EZ.addImage(imgFile, x, y);
setImagePosition();
}
private void setImagePosition() {
// Move the entire sprite sheet
zombieSheet.translateTo(x, y);
// Show only a portion of the sprite sheet.
// Portion is determined by setFocus which takes 4 parameters:
// The 1st two numbers is the top left hand corner of the focus region.
// The 2nd two numbers is the bottom right hand corner of the focus region.
zombieSheet.setFocus(walkSequence * zombieWidth, direction, walkSequence * zombieWidth + zombieWidth, direction + zombieHeight);
}
public void moveDown(int stepSize) {
y = y + stepSize;
direction = 0;
if ((counter % cycleSteps) == 0) {
walkSequence++;
if (walkSequence > 6)
walkSequence = 0;
}
counter++;
setImagePosition();
}
public void moveLeft(int stepSize) {
x = x - stepSize;
direction = zombieHeight * 2;
if ((counter % cycleSteps) == 0) {
walkSequence--;
if (walkSequence < 0)
walkSequence = 6;
}
counter++;
setImagePosition();
}
public void moveRight(int stepSize) {
x = x + stepSize;
direction = zombieHeight;
if ((counter % cycleSteps) == 0) {
walkSequence++;
if (walkSequence > 6)
walkSequence = 0;
}
counter++;
setImagePosition();
}
public void moveUp(int stepSize) {
y = y - stepSize;
direction = zombieHeight * 3;
if ((counter % cycleSteps) == 0) {
walkSequence--;
if (walkSequence < 0)
walkSequence = 6;
}
setImagePosition();
counter++;
}
// Keyboard controls for moving the character.
public void go() {
if (EZInteraction.isKeyDown('w')) {
moveUp(2);
} else if (EZInteraction.isKeyDown('a')) {
moveLeft(2);
} else if (EZInteraction.isKeyDown('s')) {
moveDown(2);
} else if (EZInteraction.isKeyDown('d')) {
moveRight(2);
}
}
public void translateBy(int i, int j) {
// TODO Auto-generated method stub
}
public int getXCenter() {
// TODO Auto-generated method stub
return x;
}
public int getYCenter() {
// TODO Auto-generated method stub
return y;
}
public int getWidth() {
// TODO Auto-generated method stub
return 0;
}
public int getHeight() {
// TODO Auto-generated method stub
return 0;
}
}
EZElement provides a getBounds property, which returns a java.awt.Shape object; why is this important? Because the Java 2D Graphics API already provides some hit detection.
From this, we then need to determine the player shape's intersection with any other shapes. To do this, we need to wrap both shapes in a Area and use it to make the final determinations.
Area meArea = new Area(me.getBounds());
Area checkArea = new Area(elementToCheck.getBounds());
checkArea(meArea);
if (!checkArea.isEmpty()) {
//... We have collision
}
Obviously, this should all be wrapped up in some kind of method to handle the core functionality, but you could have a helper method which simply took two EZElements and return true/false if the collide
For brevity and testing, I stripped back your example, but the basic idea should continue to work
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test {
private List<EZImage> brains = new ArrayList<>(25);
private Zombie me;
public static void main(String[] args) throws java.io.IOException {
new Test();
}
public Test() {
int w = 10;
int h = 10;
//create backdrop
EZ.initialize(w * 33, h * 32);
EZ.setBackgroundColor(new Color(0, 0, 0));
me = new Zombie("Zombie.png", 0, 0);
brains.add(EZ.addImage("Brains.png", (w * 33) / 2, (h * 32 / 2)));
while (true) {
detectCollision();
// check if going to collide with wall
// we want to check this before we actually move
// otherwise, we get "stuck" in a situation where we can't move
// if no collision, we can move
/*if (EZInteraction.isKeyDown('a')) {
if (!isCollisingWall(me, -2, 0)) {
me.translateBy(-2, 0);
}
} else if (EZInteraction.isKeyDown('d')) {
if (!isCollisingWall(me, 2, 0)) {
me.translateBy(2, 0);
}
} else if (EZInteraction.isKeyDown('w')) {
if (!isCollisingWall(me, 0, -2)) {
me.translateBy(0, -2);
}
} else if (EZInteraction.isKeyDown('s')) {
if (!isCollisingWall(me, 0, 2)) {
me.translateBy(0, 2);
}
}*/
me.go();
EZ.refreshScreen();
}
}
public boolean doesCollide(EZElement element, EZElement with) {
Area a = new Area(element.getBounds());
Area b = new Area(with.getBounds());
a.intersect(b);
return !a.isEmpty();
}
public void detectCollision() {
Iterator<EZImage> obstacles = brains.iterator();
while (obstacles.hasNext()) {
EZElement next = obstacles.next();
if (doesCollide(me.zombieSheet, next)) {
System.out.println("Me = " + me.getBounds().getBounds());
System.out.println("next = " + next.getBounds().getBounds());
EZ.removeEZElement(next);
obstacles.remove();
}
}
}
public class Zombie {
EZImage zombieSheet;
int x = 0; // Position of Sprite
int y = 0;
Zombie(String imgFile, int startX, int startY) {
x = startX; // position of the sprite character on the screen
y = startY;
zombieSheet = EZ.addImage(imgFile, x, y);
setImagePosition();
}
public Shape getBounds() {
return zombieSheet.getBounds();
}
private void setImagePosition() {
// Move the entire sprite sheet
zombieSheet.translateTo(x, y);
}
public void moveDown(int stepSize) {
y = y + stepSize;
setImagePosition();
}
public void moveLeft(int stepSize) {
x = x - stepSize;
setImagePosition();
}
public void moveRight(int stepSize) {
x = x + stepSize;
setImagePosition();
}
public void moveUp(int stepSize) {
y = y - stepSize;
setImagePosition();
}
// Keyboard controls for moving the character.
public void go() {
if (EZInteraction.isKeyDown('w')) {
moveUp(2);
} else if (EZInteraction.isKeyDown('a')) {
moveLeft(2);
} else if (EZInteraction.isKeyDown('s')) {
moveDown(2);
} else if (EZInteraction.isKeyDown('d')) {
moveRight(2);
}
}
}
}
I would recommend that you give each entity (and block/tile) a collision box, then test if a specific entity's bounding box collided with another entity's bounding box, then make it so that the entities can't move in that direction until there isn't a bounding box in a direction, if that made any since.
Do the same for testing for the brains, though I recommend making an ArrayList of brains, and removing specific ones if that brain had been touched.

Position of player is incorrectly calculated

In my player class the position vector of the player is consistently adding to the velocity vector of the class. I have an oldPosition Vector as well to see if the player has moved. I am using a 2d boolean array for collision throughout my game.
Here is the Player class.
public Player(){
this.velocity = new Vector2();
this.position = new Vector2(MapGrid.MAP_WIDTH / 2, MapGrid.MAP_HEIGHT + 200);
this.oldPosition = position;
this.gridPosition = new Vector2((int)(this.position.x / MapGrid.CELL_SIZE), (int)(this.position.y / MapGrid.CELL_SIZE));
}
public void create(){
this.canFall = true;
}
public void update(){
velocity.x += MainScreen.GRAVITY.x;
System.out.println("Grid calc x- " + (int)(this.position.x / MapGrid.CELL_SIZE));
System.out.println("Grid calc y- " + (int)(this.position.y / MapGrid.CELL_SIZE));
System.out.println("position top x- " + this.position.x);
System.out.println("position top y- " + this.position.y);
this.gridPosition.x = (int)(this.position.x / MapGrid.CELL_SIZE);
this.gridPosition.y = (int)(this.position.y / MapGrid.CELL_SIZE);
oldPosition.x = getGridPosition().x;
oldPosition.y = getGridPosition().y;
position.x += velocity.x;
position.y += velocity.y;
if(oldPosition.x == getGridPosition().x || oldPosition.y == getGridPosition().y){
hasMoved = false;
}
else{
hasMoved = true;
}
if(!canFall){
velocity.y = 0;
}else
velocity.y += MainScreen.GRAVITY.y;
if(Gdx.input.isKeyPressed(Keys.A)){
velocity.x -= 10 * Gdx.graphics.getDeltaTime();
}
else if(Gdx.input.isKeyPressed(Keys.D)){
velocity.x += 10 * Gdx.graphics.getDeltaTime();
}else
velocity.x = 0;
System.out.println("position after input x- " + this.position.x);
System.out.println("position after input y- " + this.position.y);
}
and here is the MapGrid class.
CELL_SIZE = 50
public void create(){
for(int x = 0; x < mapGrid.length; x++){
for(int y = 0; y < mapGrid[x].length; y++){
mapGrid[x][y] = false;
}
}
}
public void addToMap(Collidables object){
objectList.add(object);
}
public void update(){
for(int l = 0; l < objectList.size(); l++){
mapGrid[(int) objectList.get(l).getGridPosition().x][(int) objectList.get(l).getGridPosition().y] = true;
if(objectList.get(l).hasMoved()){
mapGrid[(int) objectList.get(l).getOldGridPosition().x][(int) objectList.get(l).getOldGridPosition().y] = false;
}
if(!objectList.get(l).isAlive()){
mapGrid[(int) objectList.get(l).getGridPosition().x][(int) objectList.get(l).getGridPosition().y] = false;
objectList.get(l).destroy();
}
}
}
and lastly the collision handler class
private Entity entity;
private MapGrid mapGrid;
public CollisionHandler(MapGrid mapGrid, Entity entity){
this.entity = entity;
this.mapGrid = mapGrid;
}
public void update(){
}
#Override
public void run() {
if(mapGrid.getGrid()[(int) (entity.getGridPosition().x + 1)][(int) entity.getGridPosition().y]){
entity.setCanMoveRight(false);
}else
entity.setCanMoveRight(true);
System.out.println("X: " + (int) (entity.getGridPosition().x - 1));
System.out.println("Y: " + (int) (entity.getGridPosition().y));
/*=============================*/
/*ONE LINE UNDER IS WHERE THE */
/*=========ERROR LIES!=========*/
/*=============================*/
if(mapGrid.getGrid()[(int) (entity.getGridPosition().x - 1)][(int) entity.getGridPosition().y]){
entity.setCanMoveLeft(false);
}else
entity.setCanMoveLeft(true);
if(mapGrid.getGrid()[(int) (entity.getGridPosition().x)][(int) entity.getGridPosition().y - 1]){
entity.setCanFall(false);
}else
entity.setCanFall(true);
}
When I run the game the game shows for a couple seconds and then crashes with the following error report.
The first two lines(grid calc) calculate where the player is in the grid, which is the players position / the cell size of the grid.
The second two lines(position top) of the console is the players position on screen.
The third two lines (position after input) is the same log as the normal position but I printed it at the bottom of the update method after the input.
And lastly the fourth 2 lines are printed from the collision handlers run method where the error lies.
I can't seem to find why the players grid coordinates are seemingly being divided constantly when in fact that is not happening. The grid coordinates are based on the players position divided by the cell size(50) and yet the players grid coordinates are being sent to -1 which is of course what is causing the error. I have looked everywhere and really need help here.

2D Collision issues in Java game

I've been working on this game with LWJGL for a few weeks now. Ever since I added the ability to jump, the upward collision has been giving me a lot of problems.
The game is a 2D tile-based sidescroller. Overall, the collision is almost perfect except for when the player jumps. At first I thought "Oh, maybe I just need to change the jumping mechanics," but then I realized that it only happens when the player is passed a certain x coordinate.
Now, for the actual problem itself: if the player jumps when passed a certain x coordinate, they will pass through the tile and testing for top collision returns false.
This is the entire Player class:
package Minecraft2D;
import static Minecraft2D.World.BLOCK_SIZE;
import Minecraft2D.Tools.Tools;
import Minecraft2D.UI.Inventory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import static Minecraft2D.Boot.*;
import org.lwjgl.util.Rectangle;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
public class Player {
private float x;
private float y;
public int width = 32;
public int height = 50;
private float DX = 0;
private float DY = 0;
private Texture left = null;
private Texture right = null;
Texture texture = null;
public boolean direction[] = { false, false, false, false };
public boolean collision = false;
public boolean ground = false;
public boolean jump = false;
public boolean top = false;
public Player(float x, float y) {
this.x = x;
this.y = y;
try {
this.left = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_left.png")));
this.right = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_right.png")));
this.texture = this.right;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void draw() {
Tools.drawTexture((int)x, (int)y, width, height, texture);
}
public void checkCollision(Player player, Block block) {
if (player.getY() < block.getY() + BLOCK_SIZE && player.getX() < block.getX() + BLOCK_SIZE && player.getY() + this.height > block.getY() && player.getX() + this.width > block.getX() && block.getType() != BlockType.AIR) {
Rectangle top = new Rectangle();
top.setBounds((int) player.x + 4, (int) player.y + 1, this.width - 8, 1);
Rectangle bottom = new Rectangle();
bottom.setBounds((int) player.x + 4, (int) player.y + this.height, this.width - 8, 1);
Rectangle left = new Rectangle();
left.setBounds((int) player.x, (int) player.y + 1, 1, this.height - 5);
Rectangle right = new Rectangle();
right.setBounds((int) player.x + player.width, (int) player.y + 1, 1, this.height - 5);
Rectangle blok = new Rectangle();
blok.setBounds((int) block.getX(), (int) block.getY(), BLOCK_SIZE, BLOCK_SIZE);
if (bottom.intersects(blok)) {
player.setY((block.getY() - this.height - 1));
ground = true;
jump = false;
} else if (top.intersects(blok)) {
DY = 0;
this.top = true;
y -= (player.y) - (block.getY() + BLOCK_SIZE);
}
if (!top.intersects(blok)) {
if (left.intersects(blok)) {
player.setX(block.getX() + this.width);
} else if (right.intersects(blok)) {
player.setX(block.getX() - this.width);
}
}
} else {
collision = false;
ground = false;
}
if (!collision && !jump) {
setDY(.003f);
}
if (ground && !jump) {
DY = 0;
}
if (jump && DY < 0.003f) {
DY += 0.0001;
} else {
// jump = false;
}
if (top) {
DY = 0f;
top = false;
}
x += DX;
y += DY;
if (x > Boot.SCREEN_WIDTH) {
x = 0;
}
if (x < 0) {
x = Boot.SCREEN_WIDTH;
}
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public void setDX(float dx) {
this.DX = dx;
}
public void setDY(float dy) {
this.DY = dy;
}
public void setJump() {
if (!jump) {
jump = true;
ground = false;
DY = -0.13f;
y -= 1;
}
}
public void setTexture(int tex) {
if (tex == 0) {
this.texture = this.left;
}
if (tex == 1) {
this.texture = this.right;
}
}
}
==============
EDIT: I have no clue why, but as my character moves closer to the map's 0 x-coordinate, the character's y coordinate increases very slowly. This probably has something to do with the problem I have been getting. I am looking into it and I have a suspicion that it may have something to do when I cast the player's x and y values from doubles to integers for use in the top, bottom, left, and right Rectangles.
EDIT again:
I don't know if this matters, but I have been checking collision like this: (This is in the "Boot" class.)
private void checkCollision() {
for (int x = 0; x < BLOCKS_WIDTH - 1; x++) {
for (int y = 0; y < BLOCKS_HEIGHT - 1; y++) {
Block blk = grid.getAt(x, y);
player.checkCollision(blk);
}
}
}
Why are you passing a player into checkCollision? It seems like you should not be passing in a player, but instead using the members of the player that's calling the checkCollision method. I think that may be leading to some confusion for you. Such as:
y -= (player.y) - (block.getY() + BLOCK_SIZE);
This looks like you are trying to push the player below the block b/c they intersected it during their jump. If that's the case, it should just be
y = (block.getY() + BLOCK_SIZE);
I would remove the player from the function argument and rewrite the function and see what you get. Hope that helps.
EDIT
Your comment states that you can no longer pass the player into the function. Not sure about your exact implementation, but here's what games that I have typically seen look like:
public class Player
{
private int x, y, dx, dy;
public void checkCollision(Block block)
{
if (isTopCollision(block))
fall(block.getY() + block.getHeight());
}
private boolean isTopCollision(Block block)
{
return y > block.getY() + block.getSize() && y < block.getY();
}
private void fall(int adjustedY)
{
y = adjustedY;
top = true;
dy = 0;
// etc
}
}
public class MyGame
{
public void gameloop()
{
for (Block b : blocks)
player.checkCollision(b);
}
}

Categories