Java rpg collision detection - java

So im working on a java RPG and I am stuck on the collision detecting. This is my map so far
Im trying to get it so that he cant walk on the blue but can on the white ones. The way I am doing the movement is by making the map move by applying x offset and y offset to each textures x and y, and adding/taking away from them as the wasd keys are pressed. This gives the affect that the player is moving,even though its the map. This is the code I tryed for the detection.
int x_offset = InGame.current_level.xoffset;
int y_offset = InGame.current_level.yoffset;
Rectangle player = new Rectangle(Math.round((x + x_offset) / 256),Math.round((y + y_offset) / 256),256,256);
for(int x = 0;x!= InGame.current_level.width;x++){
for(int y = 0;y!= InGame.current_level.height;y++){
int tile = InGame.current_level.tiles[x+y* InGame.current_level.width];
Rectangle tileRect = new Rectangle(x + x_offset ,y + y_offset,256,256);
if(player.contains(tileRect)){
System.out.println("Standing on " + tile);
return;
}
}
}
But somtimes it says that he is not standing on any tile,and it is often wrong when it says he is on a tile. Each Tile is rendered by doing (x * 256) + xoffset and the same for y. the map is stored in int[] where each part of the array is a number,which corresponds to a tile id

Related

processing: trouble using global array in if condition in for loop

I am trying to write a small program that has a given number of balls (in the example code below it's 3) travel back and forth across the screen at different speeds and phases (start offset).
This much has been achieved in the code. Although I want to be able to select the balls (one at a time) using a mouse click.
I have used the word "HIT!!!" to signify in the console that a ball has been clicked.
My problem is that when I run the code below, I only get a "HIT!" in the console when I click the top ball. That is when the first element y[0] matches with the click_Y variable. When I am sure (but obviously mistaken somehow) that there should be matches when I click in the vicinity of y[1] & y[2].
I'd really be grateful for any help with these. As it's gotten to the point where I am starting to stare blankly at the screen. Thanks.
int noCircles; // the number of items in the array (# of circles)
float[] y; // y-position of each circle (fixed)
float[] speed; // speed of each circle
float[] phase; // phase of each circle
float red = 120;
float green = 120;
float blue = 120;
float click_X;
float click_Y;
void setup() {
size(500, 500);
noCircles = 3;
// allocate space for each array
y = new float[noCircles];
speed = new float[noCircles];
phase = new float[noCircles];
// calculate the vertical gap between each circle based on the total number
// of circles
float gap = height / (noCircles + 1);
//setup an initial value for each item in the array
for (int i=0; i<noCircles; i++) {
y[i] = gap * (i + 1);
// y is constant for each so can be calculated once
speed[i] = random(10);
phase[i] = random(TWO_PI);
}
}
void draw() {
background(155);
for (int i=0; i<noCircles; i++) {
// calculate the x-position of each ball based on the speed, phase and
//current frame
float x = width/2 + sin(radians(frameCount*speed[i] ) + phase[i])* 200;
if (dist(x, y[i], click_X, click_Y) <= 20){
println("HIT!!!!!!!!!!!!!!!!!!");
}
ellipse(x, y[i], 20, 20);
click_X = 0;
click_Y = 0;
}
}
void mousePressed() {
println("You clicked******************************************");
click_X = mouseX;
click_Y = mouseY;
println("click_X =" + click_X);
println("click_Y =" + click_Y);
}
Problems like these are best solved by debugging your program. Start by tracing through the code by hand, then add print statements (more than you've already added), and if that doesn't work then don't be afraid to use the debugger.
You're using the click_X and click_Y variables to check the position of the mouse against the position of each ball. Trace through the for loop in your draw() function. What happens at the end of the first iteration?
You reset the values of click_X and click_Y. That's why you aren't detecting any hits on the other circles.
You could probably refactor your code to only reset those variables if something has been hit, but really, I would stop using them altogether.
I'm guessing that you're using those variables because you only want to check when the mouse is pressed? Just use the mousePressed variable for that. Then you can use the mouseX and mouseY variables directly.
Then your if statement would look like this:
if (mousePressed && dist(x, y[i], mouseX, mouseY) <= 20) {
println("HIT: " + i);
}
Also, using separate arrays like this is called parallel arrays, and is general a bad habit to get into. You should probably use classes instead.

Get tile player is standing on (player doesn't move according to (isometric) TiledMap LibGDX

I'm developing a game resembling the popular 'Warlock' custom map from WC3. For the game I am using a tiledmap, however the player does not (and is not supposed to) move using the LibGDX tiledmap api. Instead the player moves by vectors. I'm trying to register which tile the player is standing on, by taking in the player's world coordinates and finding the respective Row and Column for that exact tile.
I seem to have it properly working for an orthographic tiledmap with the following piece of code:
private boolean checkIfOnLava()
{
for (Entity e : world.getEntities(PLAYER)) {
float height = currentLayer.getTileHeight() * currentLayer.getHeight();
float width = currentLayer.getTileWidth() * currentLayer.getWidth();
float playerX = e.get(Position.class).getX();
float playerY = e.get(Position.class).getY();
int tileRow = (int) (playerX / currentLayer.getTileWidth());
int tileCol = (int) Math.abs((playerY - (height / 2)) / currentLayer.getTileHeight());
System.out.println("Row: " + tileRow);
System.out.println("Col: " + tileCol);
if (currentLayer.getCell(tileRow, tileCol).getTile().getId() == 3) {
System.out.println("Walking on lava");
return true;
}
}
System.out.println("walking on ground");
return false;
}
However, when working with an isometric map it seems a bit more tricky to find the respective column and row of the tile. I think I'll have to use some math for Rombus' instead of squares, but I'm not sure if thats correct, and if so, which math to use.
I found a solution to my problem, with the use of the following method, it can now identify the Row and Column of the tile the player is standing on, based on its position in pixels.
private boolean OnLava()
{
for (Entity e : world.getEntities(PLAYER)) {
float playerX = e.get(Position.class).getX();
float playerY = e.get(Position.class).getY();
int tileRow = (int) (playerX / currentLayer.getTileWidth() - (playerY / currentLayer.getTileHeight()));
int tileCol = (int) Math.abs((tileRow * currentLayer.getTileHeight() / 2 + playerY) / (currentLayer.getTileHeight() / 2));
if (currentLayer.getCell(tileRow, tileCol).getTile().getId() == 3) {
return true;
}
}
return false;
}

Beginner JavaFX, tracking a max radius generated randomly?

I have a project where I have to fill a 600x400 window (JavaFX) with 30 random sized circles with no filling. The largest circle must be filled with a translucent red (and if there are multiple large circles with the same radius only one can be filled). I'm able to get all the circles on the screen fine. My problem is getting the largest circle to be red. I haven't been taught arrays which were used in almost all of my many google searches. I cant figure out how exactly to track the largest circle. His hint to us is : "When it comes to keeping track of the largest circle, remember that two reference variables can point to the same Circle object. Maintain a separate Circle reference variable that always points to the largest circle (so far created). You may want to initialize this variable to a circle that has a radius of 0. You can get the radius of a circle using the getRadius method." I created a circle object and a largestCircle object but don't understand how to make the largestCircle object have the highest radius.
This is the code I have so far:
{
Random gen = new Random();
int x = 0;
int y = 0;
int radius = 0;
double largestRadius = Math.max(radius);
Circle largestCircle = null;
Group root = new Group();
//prints out 30 circles
for (int i = 0; i <= 30; i++)
{
Circle circle = new Circle(x, y, radius);
{
radius = gen.nextInt(66) + 10; //generates random radius from 10 to 75
x = gen.nextInt(600 - 2 * radius) + radius;
y = gen.nextInt(400 - 2 * radius) + radius;
}
if (circle.getRadius() == largestRadius)
{
largestCircle = circle;
largestCircle.setFill(Color.rgb(255, 0, 0, 0.3));
}
circle.setFill(null);
circle.setStroke(Color.rgb(gen.nextInt(256), + gen.nextInt(256), gen.nextInt(256)));
circle.setStrokeWidth(3);
root.getChildren().add(circle);
}
after I generate the random circles how to I find the max radius that was generated and set it to largestCircle? the highest radius a circle can be is 75, but sometimes none of the circles have a radius of 75. How do I set the max to be the highest number the program randomly generates?
Any help would be greatly appreciated! Thank you for your time
How about the following.
It has a two fixes.
-1, use > and not == when figuring if current circle is the largest.
-2, change the color of the largest circle at the end, after all the circles have been made... else you might make multiple circles red.
{
Random gen = new Random();
int x = 0;
int y = 0;
int radius = 0;
double largestRadius = Math.max(radius);
Circle largestCircle = null;
Group root = new Group();
//prints out 30 circles
for (int i = 0; i <= 30; i++)
{
Circle circle = new Circle(x, y, radius);
if (circle.getRadius() > largestRadius)
{
largestCircle = circle;
}
{
radius = gen.nextInt(66) + 10; //generates random radius from 10 to 75
x = gen.nextInt(600 - 2 * radius) + radius;
y = gen.nextInt(400 - 2 * radius) + radius;
}
circle.setFill(null);
circle.setStroke(Color.rgb(gen.nextInt(256), + gen.nextInt(256), gen.nextInt(256)));
circle.setStrokeWidth(3);
root.getChildren().add(circle);
}
largestCircle.setFill(Color.rgb(255, 0, 0, 0.3));
It is generally a good idea to initialize any max variable with a small number that is out of scope for your project. In this case, since radius can not be -1, I would do
double largestRadius = -1;
After this, it doesn't matter how big the radius can be, any radius bigger than -1 will change the largestRadius.
It looks to me like you are only missing one part and that is the if the newly created circle has a radius > largestRadius.
if(circle.getRadius() > largestRadius){
largestCircle = circle;
largestRadius = circle.getRadius();
}
After this, you have checked for if the new circle has a radius greater than AND you have checked if the new circle has a radius equal to. Keeping the if statement that you already have, you will always reference the newest circle with the largestRadius.
I would keep the circle objects in an array. Use a double (or whatever number type is appropriate for your random values) to track the high value with a simple comparison (is my current high value less than the new random value? if so, update high value) each time you generate a random value and create a circle of that size.
Once you have your 30 circles in your array simply loop through it until you find the first occurrence of your high value, when you find it make that circle whatever color.
Circle[] myCircles=new Circle[30];
double largestCircle;
for(int i=0;i<30;i++){
// determine your x,y, and radius here
myCircles[i]=new Circle(x,y,radius);
if(radius>largestCircle) largestCircle=radius;
}
Then to loop thru your myCircles and do things with each one
for(int i=0;i<30;i++){
if(myCircles[i].getRadius()==largestCircle){
// make myCircles[i] red here
}
}

Detecting ball collision with a user-added square

Basically I have been asked to create a pinball game that fires a ball on to a board and the user can control flippers etc to keep the ball from hitting an absorber with added shapes to act as bumpers to keep the ball in play.
However, I've run in to a little problem with my collisions. The user can click a grid square on the board to highlight it and then use the 'Add Square' button to add a square of height 20 and width 20 to that highlighted square also returning its (x,y) position.
public void addASquare(Point p) {
System.out.println("Add square to point: " + p.x + ", " + p.y);
Square square = new Square(p.x, p.y, L, L);
bumperList.add(square);
setChanged();
notifyObservers(bumperList);
}
Once, this has been done I then add Line Segments to the square using the (x,y) coordinates from the use adding the square to prepare for collision detection with a ball.
public ArrayList<LineSegment> getLineSeg() {
ArrayList<LineSegment> lines = new ArrayList<LineSegment>();
LineSegment l1 = new LineSegment(x, y, x + 1, y); // top
LineSegment l2 = new LineSegment(x, y + 1, x + 1, y + 1); // bottom
LineSegment l3 = new LineSegment(x, y, x, y + 1); // left
LineSegment l4 = new LineSegment(x + 1, y, x + 1, y + 1); // right
lines.add(l1);
lines.add(l2);
lines.add(l3);
lines.add(l4);
return lines;
}
..and here is the code for the collision detection when the ball hits either side of the square.
ArrayList<LineSegment> lseg = sq.getLineSeg();
for (LineSegment line : lseg) {
time = Geometry.timeUntilWallCollision(line, ball,
velocity);
if (time < minimumTime) {
minimumTime = time;
newVelocity = Geometry.reflectWall(line, ball.getVelocity(), 1.0);
return new CollisionDetails(minimumTime, newVelocity);
}
}
However, when I run the program the ball just carries on through the square. I think I am overlooking some key detail that I can't seem to solve which is why I'm here, so any help or pointers at all will be greatly appreciated.
You say your square has side lengths of 20 units which I suppose is the value of your constant L but your line segments only have a length of 1. Try replacing the values of 1 by your constant L.

A fast collision detection between a circle and a sprite in pixel perfect

I've been thinking on some fast and brilliant pixel - perfect collision detection between a circle and any sprite. I need to get 2 points of collision to be able to calculate a normal vector out of them later. I managed to come up with some solution but the more scaling is done in my game, the more inaccurate and unprecise this collision is...It seems as if the code I posted below, was good and correct becouse I have been checking it already a few times and spent a few days reading it again and again... I also checked visually that the collision masks and areas of collision are calculated perfectly fine in the code below so the problem definitely doesn't lay there but in this method.
So I guess that the problem here is the loss of data in floating point arithmetic unless somebody finds a flaw in this method?
If however the problem is really with the float loss of data, what other solution would you recommend to find 2 points of collision between circle and any other sprite in pixel perfect? I really liked my solution becouse it was relatively fast
int xOffset1 = (int)colRectLeft; // left boundary of the collision area for the first sprite
int xOffset2 = (int)colCircleLeft; // left boundary of the collision area for the circle sprite
int yOffset1 = (int)colRectBottom; // bottom boundary of the collision area for the first sprite
int yOffset2 = (int)colCircleBottom; // bottom boundary of the collision area for the circle sprite
int width = (int)(colCircleRight - colCircleLeft); //width of the collision area - same for both sprites
int height = (int)(colCircleTop - colCircleBottom); // height of the collision area same for both sprites
// Pixel-perfect COLLISION DETECTION between circle and a sprite
// my custom vector classes - nothing special
Math2D.Vector_2 colRightPoint = new Math2D.Vector_2(-1, -1); // The right point of collision lying on the circle's circumference
Math2D.Vector_2 colLeftPoint = new Math2D.Vector_2(-1, -1); // the left point of collision lying on the circle's circumference
boolean colRightFound = false;
boolean colLeftFound = false;
// I'm going through y in the circle's area of collision
for (float y = yOffset2; y < yOffset2 + height; y += 1)
{
// from equation: (x-Sx)^2 + (y-Sy)^2 = r^2
// x1/2 = (+-)sqrt(r^2 - (y - Sy)^2) + Sx
//(Sx, Sy) is (circle's radius, circle's radius) becouse I want the points on the circle's circumference to have positive coordinates
float x1 = (float) (Math.sqrt(radius*radius - (y - radius)*(y - radius)) + radius); // the right pixel on the circumference
float x2 = (float) (-x1 + 2*radius); // the left pixel on the circumference
//first I check if the calculated x is inside of the previously calculated area of collision for both circle's area and a sprite's area
if (x1 >= xOffset2 &&
x1 <= xOffset2 + width &&
xOffset1 + x1 - xOffset2 < rectFrameW &&
yOffset1 + (int)y-yOffset2 < rectFrameH &&
yOffset1 + (int)y-yOffset2 > 0 &&
xOffset1 + x1 - xOffset2 > 0)
{
//I don't have to check if the point on the circle's circumference is opaque becouse it's always so just check if the same point translated to sprite's area of collision is opaque
boolean opaqueRectPixel = go.gameData.images.get(go.pic_nr)
.collision_mask[(int)((yOffset1 + (int)y-yOffset2)*rectFrameW +
(xOffset1 + x1 - xOffset2))];
if(opaqueRectPixel)
{
if(!colRightFound)
{
colRightPoint.x = (xOffset1 + x1 - xOffset2);
colRightPoint.y = (yOffset1 + (int)y - yOffset2);
colRightFound = true;
}
else if(!colLeftFound)
{
colLeftPoint.x = (xOffset1 + x1 - xOffset2);
colLeftPoint.y = (yOffset1 + (int)y - yOffset2);
}
}
}
//the same logic for the left point on the circle's circumference
if (x2 >= xOffset2 &&
x2 <= xOffset2 + width &&
xOffset1 + x2 - xOffset2 < rectFrameW &&
yOffset1 + (int)y-yOffset2 < rectFrameH &&
yOffset1 + (int)y-yOffset2 > 0 &&
xOffset1 + x2 - xOffset2 > 0)
{
boolean opaqueRectPixel = go.gameData.images.get(go.pic_nr)
.collision_mask[(int)((yOffset1 + (int)y-yOffset2)*rectFrameW +
(xOffset1 + x2 - xOffset2))];
if(opaqueRectPixel)
{
if(!colLeftFound)
{
colLeftPoint.x = (xOffset1 + x2 - xOffset2);
colLeftPoint.y = (yOffset1 + (int)y - yOffset2);
colLeftFound = true;
}
else if(!colRightFound)
{
colRightPoint.x = (xOffset1 + x2 - xOffset2);
colRightPoint.y = (yOffset1 + (int)y - yOffset2);
}
}
}
// if both points are already found, finish
if(colLeftFound && colRightFound)
break;
}
edit: Actually, what I'm doing in this method is finding points of intersection between circle and a sprite
edit: Ok, I'm uploading images to describe my algorithm a bit better. I really tried my best to explain it but if there's still something missing, let me know please!
Also I would accept any other good solutions to find intersection points between a circle and any sprite in pixel perfect, if you don't want to check my code :(... Eh, I'm always having problems with collisions...
If you absolutely want (or need) pixel perfect, your solution looks good.
don't forget to first make a rectangle-to-rectangle collision before testing a pixel perfect detection, to avoid unneeded processings.
If you want another accurate method which maybe more efficient, look for Separating Axis Theorem.
You can find more information about it here :
http://rocketmandevelopment.com/blog/separation-of-axis-theorem-for-collision-detection/
and here :
http://www.metanetsoftware.com/technique/tutorialA.html
The last one have nice interactive explanation and demonstration. Enjoy :)
...as I was not able to show the raster in the comments:
I did not mentally parse your code, however from the image I see that you try to detect borderline collisions. Putting round or diagonal (border)lines into a raster may cause occasions, where two crossing lines do not overlay each other - like this:
1 2
2 1
whereby 1 would be line 1 and 2 would be line 2.
However I still like the idea of checking border lines combined with rectangle pre-checks. If you would render an array of raster proved-closed line coordinates by sprites you could check them against each other. This could also be enriched by border line segmenting (such as North, East, West and South or a bit more fine grain - I guess there is an optimum). A diagonal proved-closed line in the check data set must represent something like this:
x _
x x
whereby the x represent the pixels of your line and the _ is an empty raster seat.

Categories

Resources