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
Related
I want to sample a height map for my 3D engine. It might happen that there are more vertices on my terrain than pixels in my image. I created following method:
public float interpolateFromImage(BufferedImage image, float x, float y){
This takes the image and the x and y coordinate. The coordinates are given in percent.
My approach was to calculate the distances between the nearby pixels and the given coordinate. This worked fine but I ended up with this:
It can be clearly seen that the edges are not as smooth as they should be.
I used following code:
int topLeftX = (int) (x * (image.getWidth()-1)); //index of topLeft pixel
int topLeftY = (int) (y * (image.getHeight()-1)); //index of topLeft pixel
float[] distances = new float[4];
float total = 0;
for(int j = topLeftX ; j < topLeftX + 2; j++){ //run through all 4 nearby pixels
for(int k = topLeftY ; k < topLeftY + 2; k++){
float dist = (float) Math.sqrt( //pythagoras for the distance
(x- j/ (float)(image.getWidth()-1)) *
(x- j/ (float)(image.getWidth()-1)) +
(y- k/ (float)(image.getHeight()-1)) *
(y- k/ (float)(image.getHeight()-1)));
if(dist < 0.001){
return new Color(image.getRGB(j,k)).getRed();
}
distances[(j-topLeftX) * 2 + (k-topLeftY)] = (1f / image.getWidth()) / (dist * dist);
total += distances[(j-topLeftX) * 2 + (k-topLeftY)];
}
}
float h = 0;
for(int j = topLeftX ; j < topLeftX + 2; j++){
for(int k = topLeftY ; k < topLeftY + 2; k++){
float p = distances[(j-topLeftX) * 2 + (k-topLeftY)] / total;
h+= new Color(image.getRGB(j,k)).getRed() * p;
}
}
return h;
Does anyone know how I need to change my code ?
I am very happy for any advice and help :)
You are weighing the colors based in the inverse squared distance from all four corners. The problem here is this: the pixel colors on the edge are affected by the color of the corners across. The pixel colors on the two sides on the edges differ because they are calculated from a different set of four corners.
Solution is to use some common interpolation, like bilinear or bicubic interpolation.
Allright, I'm working on a small game here in Java, and I am using this Simplex Noise generator I found online. The problem that I am facing, is this: I'm generating the world of my game like so:
int width = 100;
int height = 100;
world = new int[width * height];
SimplexNoise noise = new SimplexNoise();
for (int i = 0; i < world.length; i++) {
int x = i % width; // what are the coordinates from i ?
int y = i / width ;
int frequency = 15;
float h = (float) noise.noise((float) x / frequency, (float) y / frequency);
if (h >= -1 && h <= 0) {
world[x + y * width] = 0; // air tile
}
else if (h > 0 && h <= 1) {
world[x + y * width] = 1; // test tile
}
}
which quite obviously gives me 2D noise. The end result looks like this:
As far as I understand noise, 2D noise is for top-down games. The one I'm working on, is a side-scroller (like Terraria, Starbound, Crea and others), though. So I'd need a terragen to give me the topmost layer of the terrain, google tells me that is 1D noise, so here's the question: How to convert this 2D noise into a terrain-looking 1D noise?
Just make it a picture of height = 1. Done :)
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
How can I draw a line on the console if I have a 2D array of chars. The function I want to write is something like:
This is my first attempt, but it looks totally wrong
public static void line(char[][] mPixels, int startRow, int startColumn, int endRow, int endColumn)
{
double dY = endRow - startRow;
double dX = endColumn - startColumn;
double slope = dX / dY;
slope = Math.abs(slope);
if(slope >= 1)
{
double progress = -(dY / dX);
for(int i=startColumn; i<=endColumn; i++)
{
double j = startRow - (int) ((i-startColumn) * progress);
int yLoc = (int) (Math.round( j * 100.0 ) / 100.0);
mPixels[i][yLoc] = '*';
}
}
// print array
}
use DDA or Bresenham,...
What you have looks like DDA but you do not handle slopes correctly. You should divide by the axis with bigger amount of pixels and use it as control axis so:
if |dx|>|dy| then for goes through x = x0 -> x1 and y=y0+((x-x0)*dy/dx)
if |dx|<|dy| then for goes through y = y0 -> y1 and x=x0+((y-y0)*dx/dy)
if they are equal then use any of above.
if dx==0 and dy==0 draw just dot and no for is present
Do not forget to handle if main axis is ascending or descending (can be x++,y++ or x--,y--) also can be done on integer only without division or multiplication but that is another story
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.