I am a visual learner working on a simple 2D game that requires balls to bounce off of each other with no spin.
I have followed the code in many links and chose to use the example found at Ball to Ball Collision - Detection and Handling
My code however results in both the ball accelerating out of control and also somehow removing balls from the playing field on striking. If someone could describe my errors to me that would be much appreiated. However I would find just as much help in step by step pictures describing the math behind the collisions found in the link above.
public void resolveCollision2(PoolBall ball) {
vector delta = new vector(getXPos() - ball.getXPos(), getYPos() - ball.getYPos());
float d = (float) delta.getMagnitude();
vector mtd = delta.scalerMultiply((32.0 - d) / d);
vector reset = mtd.scalerMultiply(0.5);
XPos = XPos + reset.getXlen();
YPos = YPos + reset.getYlen();
ball.setXPos(ball.getXPos() - reset.getXlen());
ball.setYPos(ball.getYPos() - reset.getYlen());
vector v1 = new vector(getXVel(), getYVel());
vector v2 = new vector(ball.getXVel(), ball.getYVel());
vector v = v1.subtract(v2);
float vn = v.dot(mtd.normalize());
if(vn > 0.0f) return;
float i = (-(1.0f + 0.1f) * vn);
vector impulse = mtd.scalerMultiply(i);
vector v1prime = v1.add(impulse);
vector v2prime = v2.subtract(impulse);
setXVel(Math.sqrt(v1prime.getXlen()));
setYVel(Math.sqrt(v1prime.getYlen()));
ball.setXVel(Math.sqrt(v2prime.getXlen()));
ball.setYVel(Math.sqrt(v2prime.getYlen()));
}
public void poolBallPoolBallCollision() {
double XDif = 0.0;
double YDif = 0.0;
double XDif2 = 0.0;
double YDif2 = 0.0;
for (int i = 0; i < 15; i++) {
for (int j = i + 1; j < 15; j++) {
if (colliding(ballList[i], ballList[j])) {
ballList[i].resolveCollision2(ballList[j]);
}
}
}
}
Things to note
balls have equal mass
no friction
no spin
Related
I am trying to make a 2D game in LWJGL. I am having a problem with terrain generation. I currently have an algorithm to generate terrain but it is always random and I can never get that same world again I would like to make an algorithm that generates a x and y coordinates based on a given number.
My current world generation looks like this:
final float STEP_MAX = 1f;
final float STEP_CHANGE = 1;
final int HEIGHT_MAX = 100;
double height = HEIGHT_MAX;
double slope = STEP_MAX;
for (int x = -WORLDSIZE; x < WORLDSIZE; x++) {
height += slope;
slope += (Math.random() * STEP_CHANGE) * 2 - STEP_CHANGE;
if (slope > STEP_MAX) slope = STEP_MAX;
if (slope < -STEP_MAX) slope = -STEP_MAX;
if (height > HEIGHT_MAX) {
height = HEIGHT_MAX;
slope *= -1;
}
if (height < 0) {
height = 0;
slope *= -1;
}
Tile newTile = new Tile(x*25,(int)height*25,25,25,TileType.Grass);
tiles.add(newTile);
Thank you in advance for your help.
If you create your random number generator yourself (rather than letting Math.random() do so for you), you can specify a seed:
Random random = new Random(yourSeed);
random.nextDouble();
the Random class also has many useful methods you might want to look at.
More info: https://docs.oracle.com/javase/8/docs/api/java/util/Random.html
I currently have a program with a grid and lines that will be drawn between dots in the grid. It uses standard draw. I wish to limit the length of the lines, so that they can only go from the adjacent points, but do not know how I would do this.
Thanks
StdDraw.setCanvasSize(400, 400);
StdDraw.setXscale(0, 10);
StdDraw.setYscale(0, 10);
//dots
double radius = .15;
double spacing = 2.0;
for (int i = 0; i <= 4; i++) {
for (int j = 0; j <= 4; j++) {
StdDraw.setPenColor(StdDraw.GRAY);
StdDraw.filledCircle(i * spacing, j * spacing, radius );
}
}
StdDraw.setPenColor(StdDraw.BLUE);
StdDraw.text(0, 9.5, player1_name);
StdDraw.setPenColor(StdDraw.RED);
StdDraw.text(5, 9.5, player2_name);
int turn = 1;
for (int i = 0; i <= 40; i++) {
if (turn % 2 == 0)
StdDraw.setPenColor(StdDraw.RED);
else
StdDraw.setPenColor(StdDraw.BLUE);
while(!StdDraw.mousePressed()) { }
double x = StdDraw.mouseX();
double y = StdDraw.mouseY();
System.out.println(x + " " + y);
StdDraw.setPenRadius(.01);
StdDraw.show(200);
while(!StdDraw.mousePressed()) { }
double x2 = StdDraw.mouseX();
double y2 = StdDraw.mouseY();
StdDraw.show(200);
double xround = Math.round(x);
double yround = Math.round(y);
double x2round = Math.round(x2);
double y2round = Math.round(y2);
int xroundb = (int) xround;
int yroundb = (int) yround;
int x2roundb = (int) x2round;
int y2roundb = (int) y2round;
StdDraw.line(xround, yround, x2round, y2round);
System.out.println("Line Drawn");
StdDraw.show();
Ah I get it. You are not asking about the actual line method which does work correctly, you want logic such that line is not called if adjacent dots are not selected.
Well, first we need to know which adjacent connections are allowed. That is can we have Vertical? Horizontal? Diagonal? I will explain each just in case
So you have spacing = 2.0. Well, that should be sufficient to check for adjacency.
if (Math.abs(x2round - xround) > spacing) {
// don't draw
} else if (Math.abs(y2round - yround) > spacing)) {
// don't draw
} else if (Math.abs(y2round - yround) > 0.0) && Math.abs(x2round - xround) > 0.0) {
// don't draw if diagonal connections are forbidden
// if diagonal is allowed, remove this else if condition
} else {
StdDraw.line(xround, yround, x2round, y2round);
}
So if you don't draw, then you have to enforce your game logic. Perhaps the player forfeits a turn. Perhaps the player is given another chance to select adjacent dots. It is up to you. It is always a bit crazy comparing doubles due to roundoff, so instead of using 0.0, you might want to choose a very small epsilon double value to make sure you catch all cases.
I am currently developing a 2D Mario-Like Platformer Game. I ran into a collision problem i've been trying to solve for a while now, but nothing seems to work :/
Basicly, i have a CenterLayer, which stores at which Position what kind of Tile is.
Then i have some Sprites and a Player, which should collide with these Tiles.
Because these Tiles can be triangular shaped (or any other kind of convex polygon), i decided to handle collision via SAT (Seperating Axis Theorem). This works great, but when it comes to collision with the floor where many tiles are adjacent to eachother and the sprite is moving left, it pickes the wrong edge and moves the Sprite to the right, but expected result would be moving it up. This causes the sprite to get stuck.
This is the code im currently using:
package level;
import java.awt.Polygon;
import tiles.Tile;
import sprites.*;
public class Collider {
/** Collide Sprite (or Player) with CenterLayer **/
public static void collide(Sprite s, CenterLayer c){
CollisionPolygon ps = s.getPolygon();
//Get blocks to collide with
int startXTile = (int) (s.getX() / CenterLayer.TILE_WIDTH) - 1;
int endXTile = (int) Math.ceil((s.getX() + s.getWidth()) / CenterLayer.TILE_WIDTH) + 1;
int startYTile = (int) (s.getY() / CenterLayer.TILE_HEIGHT) - 1;
int endYTile = (int) Math.ceil((s.getY() + s.getHeight()) / CenterLayer.TILE_HEIGHT) +1;
//limit to level boundaries
if(startXTile < 0) startXTile = 0;
if(endXTile > c.LEVEL_WIDTH) endXTile = c.LEVEL_WIDTH;
if(startYTile < 0) startYTile = 0;
if(endYTile > c.LEVEL_HEIGHT) endYTile = c.LEVEL_HEIGHT;
int sizeX = endXTile - startXTile;
int sizeY = endYTile - startYTile;
//loop through tiles and collide
for(int xc = 0; xc < sizeX; xc++)
for(int yc = 0; yc < sizeY; yc++){
int xblock = xc + startXTile;
int yblock = yc + startYTile;
Tile t = c.getTile(xblock, yblock);
if(t!=null){ //if tile == null --> tile is air
CollisionPolygon pt = t.getPolygon(xblock, yblock);
double[] projection = PolygonCollision(ps, pt);
//if collision has happened
if(projection[0] != 0 || projection[1] != 0){
//collide
s.moveBy(projection[0], projection[1]);
//update sprites polygon to new position
ps = s.getPolygon();
}
}
}
}
public static double dotProduct(double x, double y, double dx, double dy) {
return x * dx + y * dy;
}
// Calculate the projection of a polygon on an axis (ax, ay)
// and returns it as a [min, max] interval
public static double[] ProjectPolygon(double ax, double ay, Polygon p) {
double dotProduct = dotProduct(ax, ay, p.xpoints[0], p.ypoints[0]);
double min = dotProduct;
double max = dotProduct;
for (int i = 0; i < p.npoints; i++) {
dotProduct = dotProduct(p.xpoints[i], p.ypoints[i], ax, ay);
if (dotProduct < min) {
min = dotProduct;
} else if (dotProduct > max) {
max = dotProduct;
}
}
return new double[] { min, max };
}
// Calculate the distance between [minA, maxA](p1[0], p1[1]) and [minB, maxB](p2[0], p2[1])
// The distance will be negative if the intervals overlap
public static double IntervalDistance(double[] p1, double[] p2) {
if (p1[0] < p2[0]) {
return p2[0] - p1[1];
} else {
return p1[0] - p2[1];
}
}
public static double[] PolygonCollision(CollisionPolygon p1, CollisionPolygon p2){
boolean intersection = true;
int edgeCount1 = p1.npoints;
int edgeCount2 = p2.npoints;
double projectionX = 0;
double projectionY = 0;
double projectionDist = Double.POSITIVE_INFINITY;
//loop through all the edges
for(int edgeIndex = 0; edgeIndex < edgeCount1 + edgeCount2; edgeIndex++){
//find edges
double[] axis;
if(edgeIndex < edgeCount1){
axis = p1.getAxis(edgeIndex);
} else {
axis = p2.getAxis(edgeIndex - edgeCount1);
}
double axisX = axis[0];
double axisY = axis[1];
//System.out.println("edge: " +axisX + ", "+ axisY);
//find the projection of both polygons on current axis
final double[] proj1 = ProjectPolygon(axisX, axisY, p1);
final double[] proj2 = ProjectPolygon(axisX, axisY, p2);
//Check if polygons are intersecting, if not end loop
double id = IntervalDistance(proj1, proj2);
if(id > 0){
intersection = false;
break;
}
//Check if projection would be shorter than previous one
id = Math.abs(id);
if(id < projectionDist){
projectionDist = id;
projectionX = axisX;
projectionY = axisY;
//check if hit from "false" side
double d1x = p1.getCenterX();
double d1y = p1.getCenterY();
double d2x = p2.getCenterX();
double d2y = p2.getCenterY();
double midx = d1x - d2x;
double midy = d1y - d2y;
double dot = dotProduct(midx, midy, projectionX, projectionY);
if(dot < 0){
projectionX = -projectionX;
projectionY = -projectionY;
}
}
}
double[] result = new double[]{0, 0};
if(intersection){
//System.out.println("colliison: " + projectionX +"; "+ projectionY + ", " + projectionDist);
result[0] = projectionX * projectionDist;
result[1] = projectionY * projectionDist;
}
return result;
}
}
Any Ideas?
Tom
I had this bug too , it happens when there are parallel edges on a poly.The easy way to fix this is to project the difference between the polygon centers on the found axis.If the result is negative you would just multiply the axis by -1.
Vector aMidPoint = new Vector();
Vector bMidPoint = new Vector();
for ( Vector v : aVerts) {
aMidPoint = aMidPoint.add(v);
}
for ( Vector v : bVerts) {
bMidPoint = bMidPoint.add(v);
}
aMidPoint = aMidPoint.scalarDivision(aVerts.size());
bMidPoint = bMidPoint.scalarDivision(bVerts.size());
Vector ba = aMidPoint.subtract(bMidPoint);
if (ba.dotProduct(minOverlapVector) < 0) {
minOverlapVector = minOverlapVector.scalarMultiplication(-1);
}
This is a homework assignment.
Work 19 5/16 is the assignment
http://sites.stuycs.org/home/courses/ml2x/dyrland-weaver/work
I am running this in the program processing, which does not require main methods.
Blob was given to us. We had to make BlobRunner on our own.
Any advice on why my code isn't doing what its supposed to would be appreciated.
FIRST FILE BlobRunner
int popSize = 4;
int wobble = 2;
int numSides = 4;
float rad = 100;
int radInt = (int) rad;
float a = sqrt(popSize);
int rootPop = (int) a;
Blob[][] blobs = new Blob[popSize/rootPop][rootPop];
/*=====================================
The trickiest part of setup is to make
the screen an appropriate size for the
grid of blobs. The grid should be just
big enough to contain all of the blobs.
====================================*/
void setup() {
size ((popSize/rootPop)*(2*(radInt+3)), rootPop*(2*(radInt+3)));
populate();
}
/*=====================================
The main purpose of draw is to go through
the array of blobs and display each.
====================================*/
void draw() {
int createdSoFar = 0;
for (int i = 0; i<rootPop; i++){
for (int j = 0; j<popSize/rootPop; j++){
if (createdSoFar < popSize){
blobs[j][i].display();
}
createdSoFar++;
}
}
}
/*=====================================
Populate the array of blobs.
You can use any values for radius, number of sides
and wobble factor that you'd like, but you must
use x and y coordinates that ensure the blobs
are drawn in a grid without overlaping each other.
Your code should work for any reasonable value
of population (i.e. something that would fit on a
normal monitor).
====================================*/
void populate() {
for (int i = 0; i < rootPop; i++){
float y = 1;
for (int j = 0; j < (popSize/rootPop); j++){
float x = 1;
blobs[j][i] = new Blob (x*(rad+3), y*(rad+3), numSides, radInt, wobble, wobble);
x=x+2;}
y=y+2;}
}
SECOND FILE Blob
/*=====================================
A Blob object is a regular polygon variant that
can have various features.
Instance Variables:
numSides: number of sides
rad: distance from the center of the polygon
to any vertext
x: x coordinate of the center
y: y coordinate of the center
xFactor: "wobble" foctor in the x direction
yFactor: "wobble" factor in the y direction
====================================*/
class Blob {
int numSides;
int rad;
float x;
float y;
int xFactor;
int yFactor;
Blob(float cx, float cy, int sides, int r, int xf, int yf ) {
x = cx;
y = cy;
numSides = sides;
rad = r;
xFactor = xf;
yFactor = yf;
}
void display() {
float nx;
float ny;
int rx, ry;
float sy;
strokeWeight(1);
beginShape();
for( float t = 0; t <= 1; t+=( 1.0/numSides ) ) {
/*
"wobble" effect is created by adding a random number to each
x and y coordinate. The larger the x and y factors, the higher
the possible wobble value could be
*/
rx = (int)random(xFactor);
ry = (int)random(yFactor);
nx = rad * cos( 2 * PI * t ) + x + rx;
ny = rad * sin( 2 * PI * t ) + y + ry;
vertex(nx, ny);
}
endShape();
}
}
Your code runs, thus it is doing what you asked it to do and nothing more.
I asked my cat to check it out though and she was all, "the guy is re-initializing his variables inside each pass of the loop, he'll never get a grid of blobs that way. Tell him to start by moving float y = 1; float x = 1; in populate() outside of the bounds of the two for loops and start debugging from there."
Then she rolled over on to her side and I patted her.
I Have Some problem.
Let's say I have Q Icons (simple icon let say android logo) and I want to place them in a star topology against the single star center (icons) and connecting them on android canvas.
How can I do it?
any exact Links?
any algorithm information?
Essentially what you will want to do is create points around a centre, give the points an icon and a line connecting them with the centre.
Creating 2d points on a circle can be done with cosine/sine:
double angle;
point.x = offsetX + radius*Math.cos(angle);
point.y = offsetY + radius*Math.sin(angle);
Increment the angle with a suitable value for each contact and store points like this in an array or a list.
When it comes to drawing, draw your icon centred at its point (yourCanvas.drawBitmap()), and draw a line to the centre point (yourCanvas.drawLine()).
public void starTopology(Canvas mCanvas,int noOfFriends,float centerX,float centerY,int radious) {
final double PI = 3.14;
final double MARGIN = (2*PI)/noOfFriends;
final double OFFSETX = centerX;
final double OFFSETY = centerY;
final int RADIUS = radious;
float pointXCoord = 0;
float pointYCoord = 0;
double NextPositionOnCircumference = MARGIN;
Paint myCustomizedBrush = new Paint();
myCustomizedBrush.setAntiAlias(true);
myCustomizedBrush.setColor(Color.WHITE);
for(int i= 0; i < noOfFriends; i++){
pointXCoord = (float) (OFFSETX + RADIUS * Math.cos(NextPositionOnCircumference));
pointYCoord = (float) (OFFSETY + RADIUS * Math.sin(NextPositionOnCircumference));
NextPositionOnCircumference += MARGIN;
mCanvas.drawLine((float)OFFSETX, (float)OFFSETY, pointXCoord, pointYCoord, myCustomizedBrush);
pointXCoord -= 10;
pointYCoord -= 10;
mCanvas.drawBitmap(Utility.FriendProfilePic.get(i), pointXCoord, pointYCoord, null);
}
mCanvas.drawCircle((float)OFFSETX, (float)OFFSETY, 5, myCustomizedBrush);
}