@Gajet's answer is impossible to follow (so I'm not even convinced it will work), and what I think @The Communist Duck meant his solution to be...
block_y = ground_y + random() % (previousBlock_y + playerJumpHeight)
...will be heavily biased towards creating blocks with y-values centered around
ground_y + playerJumpHeight.
The easiest way to produce more satisfying results would be, rather than generate a height between
previousBlock_y + playerJumpHeight, generate a random value between
previousBlock_y - playerJumpHeight and
previousBlock_y + playerJumpHeight.
Of course, since we want to take
maxBlockHeight into consideration also, we really want to find a random value between
max(ground_y, previousBlock_y - playerJumpHeight) and
min(maxBlockHeight, previousBlock_y + playerJumpHeight). This will skew our distribution a bit (biased towards the center of the screen), but not enough to be noticeable.
The simplest way to do this would be
//delta_y is a random number between -/+ playerJumpHeight
min_y = max(ground_y, previousBlock_y - playerJumpHeight)
max_y = min(maxBlockHeight, previousBlock_y + playerJumpHeight)
range_y = max_y - min_y
block_y = random() % range_y + min_y
If you then want the block to have a random height as well, just generate a random number between
block_y to be the height.
[Edit] There is a way to have a probability of jumping down by any amount, while still giving the player equal probability of being anywhere on the screen at any given point.
Thanks to Didier Piau on the math forums for figuring this out. The full explanation is complex, so I'll leave it out; the curious can visit that page, from which I generalized this algorithm. The algorithm itself is actually pretty simple, though.
int playingFieldHeight = screen_y - ground_y;
int canonicalBlockMaxHeight = playingFieldHeight - playerHeight;
int nextBlockMaxHeight = min(currentBlockHeight + playerJumpHeight, canonicalBlockMaxHeight);
//Let's divide the screen vertically into chunks of size playerJumpHeight.
//This code makes it so that each chunk is approximately twice as likely as being chosen
//as the previous chunk
float canonicalHeightRatio = (float)canonicalBlockMaxHeight / playerJumpHeight;
float nextHeightRatio = (float)nextBlockMaxHeight / playerJumpHeight;
//The following looks complicated, but really it just ensures that the minimum is 0, the maximum is
//nextBlockMaxHeight, and everything in between is mapped logarithmically
float randomMin = pow(2, -canonicalHeightRatio);
float randomMax = pow(2, nextHeightRatio-canonicalHeightRatio);
float randomVal = randFloat(randomMin, randomMax);
float randomHeightRatio = log2(randVal)+canonicalHeightRatio;
return (int)(randomHeightRatio*playerJumpHeight) + ground_y;
//Return the log-base-2 of a number
const float log_of_2 = log(2);
float log2(float value)
return log(value) / log_of_2;
//Generates a random floating-point number between min and max
float randFloat(float min, float max)
float randomNormalized = (float)rand()/RAND_MAX; //Between 0.0 and 1.0
return randomNormalized*(max-min) + min;