Drawing mountains using 1px swing rectangles - java

I'm trying to draw mountains background using 1-width rectangles (something like integrals). I randomize the first point to the very left of the screen, randomize binary number and draw the first rectangle.
If binary number is 0, the next rectangle will be 1px lower. Else higher. And so on in the for loop.
There's a 95% chance that in the next loop the direction won't change and it will keep going higher/lower. And 5% chance the direction will change. For this I'm using randomized number from 1 to 1000.
public Landscape(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
Random rand = new Random();
int first = rand.nextInt((800 - 200) + 1) + 200;
g2d.fillRect(0, 800 - first, 1, first);
int d = first % 2;
for(int i = 1; i <= 800; i++) {
int choose = rand.nextInt((1000 - 1) + 1) + 1;
if(choose > 950) {
d = -(d);
}
if(d == -1) {
first += 1;
} else {
first -= 1;
}
g2d.fillRect(i, 800 - first, 1, first);
}
}
That's the effect I get in like half cases. Sometimes however I get something like this:
How is this possible? What's wrong here?

Here:
int d = first % 2;
d is either 1 or 0. If d is assigned 0, then if(d == -1) { is always false, and thus your graph will go monotonically downwards.
You are looking for a two state solution to decide whether the mountain goes up or down, so use a boolean. Perhaps something like:
boolean direction = rand.nextBoolean();
// 1 in 20 chance, same as 5 in 100, same as 50 in 1000 chance
if (rand.nextInt(20) == 0) {
direction = !direction;
}
if (direction) {
// ...
} else {
// ...
}
Myself, I'd look into using fractals.

Related

Replace colors in an image without having to iterate through all pixels

Let's say that I have an image like this one (in reality, I have a lot of them, but let's keep it simple)
example picture and I'd like to replace background color (that's the one that's not roads) with green color.
To do that I'd have to iterate through all of the pixels in the map and replace ones that match the color I want to remove.
But as you might think, my image is not a simple as 256x256 picture, but it's slightly bigger, it's 1440p, and the performance drop is significant.
How would I replace all of the unwanted pixels without iterating through all of the pixels.
I'm working with Processing 3 - Java(Android) and I'm currently using this piece of code:
for (x = 0; x < img.width; x++){
for (int y = 0; y < img.height; y++) {
//Color to transparent
int index = x + img.width * y;
if (img.pixels[index] == -1382175 || img.pixels[index] == 14605278 || img.pixels[index] == 16250871) {
img.pixels[index] = color(0, 0, 0, 0);
} else {
img.pixels[index] = color(map(bright, 0, 255, 64, 192));
}
}
}
Solved it with this one:
private PImage swapPixelColor(PImage img, int old, int now) {
old &= ~0x00000000;
now &= ~0x00000000;
img.loadPixels();
int p[] = img.pixels, i = p.length;
while (i-- != 0) if ((p[i]) == old) p[i] = now;
img.updatePixels();
return img;
}
It works like a charm and it takes almost no time:
Swapped colors in 140ms // That's replacing it three times(different colors ofc)

Matrixes and for loops becoming inconsistent?

This is a follow-up post to my previous question, here. I got a remarkable response to instead of using array data tracking, to use matrixes. Now, the code here works just as planned (as in, the rectangles somewhat most of the time get filled in properly with white), but it's very inconsistent. When holding the left or right mouse button the colors phase over each other in a battle of randomness, and I don't know nearly that much about why this is happening. Just for reference, I'm using Java in Processing 3.
This is a result that I made with the project. As you can see, it looks fine.
Except for that jitter when hovering over a rect, and that more than not the rectangles are not being filled in half the time. And plus, the hover color is cycling almost randomly.
int cols, rows;
int scl = 20;
boolean[][] matrix = new boolean[scl+1][scl+1];
void setup() {
size(400, 400);
int w = 400;
int h = 400;
cols = w / scl;
rows = h / scl;
}
void draw() {
background(255);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
int xpos = x*scl;
int ypos = y*scl;
stroke(55);
if ((mouseX >= xpos && mouseX <= xpos+scl) &&
(mouseY >= ypos && mouseY <= ypos+scl)) {
fill(75);
if (mousePressed == true) {
println("Clicked at: " + xpos + " and " + ypos);
if (!matrix[xpos/scl][ypos/scl]) {
matrix[xpos/scl][ypos/scl] = true;
} else {
matrix[xpos/scl][ypos/scl] = false;
}
fill(100);
//here is the desired location for the fill to remain constant even
//after unclicking and leaving hover
}
println("Mouse at: " + xpos + " and " + ypos);
} else {
fill(50);
}
if (matrix[x][y]) {
//fill(204, 102, 0);
fill(240);
rect(xpos, ypos, scl, scl);
}
rect(xpos, ypos, scl, scl);
}
}
}
Remeber that Processing fires the draw() function 60 times per second.
So your check for whether the mouse is pressed is happening 60 times per second. That means you're toggling the state of whatever cell the mouse is in 60 times per second.
To fix that problem, you might switch to using the event functions like mousePressed() instead of constantly polling every frame.
From the reference:
int value = 0;
void draw() {
fill(value);
rect(25, 25, 50, 50);
}
void mousePressed() {
if (value == 0) {
value = 255;
} else {
value = 0;
}
}
As for certain cells being skipped over, that's because when you move the mouse, it doesn't actually go through every pixel. It "jumps" from frame to frame. Those jumps are usually small enough that humans don't notice it, but they're large enough that it's skipping over cells.
One solution to this is to use the pmouseX and pmouseY variables to calculate a line from the previous mouse position to the current mouse position, and fill in any cells that would have been hit along the way.

Processing draw a rect and keep it for some time

So i've made a simple program that have as its objective to draw a rect on the screen when a button is clicked on the mouse, if its the left button it make a rect on the left half of the screen, and if it the right it make a rect in the right half of the screen.
The problem is that i used a for loop to make the rect get drew for some time continuously, but it just does not happen.
Here is my code:
int bab = 0;
void setup() {
size(500, 500);
frameRate(24);
background(255);
int b = 0;
}
void draw() {
background(255);
println(bab);
bab++;
if(mousePressed == true && mouseButton == LEFT) {
fill(100, 0, 0);
for(int i = 0; i <= 20000; i++) {
fill(100, 0, 0);
rect(0, 200, width/2, 50);
println("The value is: " + i);
}
background(255);
}else if(mousePressed == true && mouseButton == RIGHT) {
fill(255, 255, 0);
for(int i = 0; i <= 200; i++) {
rect(width/2, 0, width/2, height);
}
}
}
Try this code:
long leftOn = 0;
long rightOn = 0;
void draw() {
// clear window buffer (white color)
background(255);
if (mousePressed == true && mouseButton == LEFT) {
// remember timestamp when left button was pressed in variable leftOn
leftOn = millis();
rightOn = 0;
} else if (mousePressed == true && mouseButton == RIGHT) {
// remember timestamp when right button was pressed
rightOn = millis();
leftOn = 0;
}
// now is current timestamp
long now = millis();
/*
* if now - last left click distance is lower than 1000 ms - draw left rect
* else if now - right left click distance is lower than 1000 ms - draw right rect
*/
if (now - leftOn <= 1000*1) {
fill(0,255,0);
rect(0,0,width/2,height);
} else if (now - rightOn <= 1000*1) {
fill(255,255,0);
rect(width/2, 0, width/2, height);
}
// else - nothing is drawn in this frame, so window will be empty in this frame
}
Looping is done by Processing - I mean when you set frame rate to 20 it means that Processing will call method draw() every 50 ms (20 times in 1 second).
So, you have to implement how 1 single frame should be drawn. You dont need looping to make things last longer.
In above code left rect will appear and last for 1 second from last left button was pressed. And right rect for 1 second from right button.
The millis() method returns the number of milliseconds that elapsed from startup. You can then remember in leftOn when left button was pressed. And you draw left rect if time difference between now and last leftOn is less then 1000 ms - for example.
Your for loop uses i as it's control / to represent each iteration through the loop. You also have the drawing happening in this loop, so that each iteration should draw something.
However, nowhere in your loop do you use the i variable -- you only print it to the console.
for(int i = 0; i <= 20000; i++) {
fill(100, 0, 0); // does not use i
rect(0, 200, width/2, 50); // does not use i
println("O valor é: " + i);
}
So what you have really is a loop that draws the exact same thing, 20000 times. So to you it looks like nothing is happening, but it is, it's just the same thing is happening repeatedly.
Maybe you wanted something more like:
for(int i = 0; i <= 20000; i++) {
fill(100, 0 + i, 0 + i);
rect(0 + i, 200, width/2, 50 + i);
println("O valor é: " + i);
}
^ I really have no idea if that makese sense... But you need to use the loop control variable i somewhere in your drawing code, or else yes, you will draw the same thing repeatedly.

Random directions

Hello I am busy with learning Java and I am busy creating a pacman game but now I need to let the ghosts move in a "Random" direction and so now and then this direction has to change vertically/horizontally and vica versa
at the moment the ghost goes from left to right and right to left. the code that is responsible for this action is as follows: (ignore pacman drawing part see below //ghost movement)
DrawPacMan pacman = new DrawPacMan();
DrawGhost ghost = new DrawGhost();
int g1x = 0;
boolean g1r = true;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// pacman movement
diameter = 25;
pacman.drawPacMan(g, getHorPlaats(), getVerPlaats(), diameter, getView(), Color.yellow);
// ghosts movement
g1x += ghostSpeed * (g1r? 1 : -1);
// check direction
if (g1x >= 500) { g1x = 500; g1r = false; }
else if (g1x <= 0) { g1x = 0; g1r = true; }
ghost.drawGhost(g, g1x, 40, diameter, Color.red);
}
Now I don't know how to create a random direction or what functions to use. Can someone give me some hints/help and if possible a little example that I can work further with? and if you want to see more code or something please ask and i'll post :)
Try this:
g1x += ghostSpeed * (Math.random() > 0.5? 1 : -1);
or even simpler:
g1x += ghostSpeed * Math.signum(Math.random() - 0.5);
This exploits the fact that Math.random() returns uniformly distributed value in [0, 1).
But you'll quickly realize that such an algorithm will cause ghosts to move erratically, from left to right. You'll need something more elegant. E.g. if ghost moves to left, let him continue with 75% probability or change the direction with 25% of probability. I'll let you tackle this.
For something simple like this, I'd generate a random number, either 0, 1, 2, or 3. This will give you all the directions you need: up, down, left, and right.
import java.util.Random;
// create a random number generator
Random randomGen = new Random();
// generate a random number, between 0 and n-1 (0,1,2,3 in this case)
int theRandomNumber = randomGen.nextInt(4);
public void setRandomGhostDirection() {
switch(theRandomNumber) {
case 0:
moveUp();
break;
case 1:
moveLeft();
break;
case 2:
moveRight();
break;
case 3:
moveDown();
break;
}
}
You could clean this up by defining the direction numbers as something like
final int DIRECTION_UP = 0 etc.
Math.random() is the function that you're looking for. By itself, this function generates a random double from 0 to 1.
Pseudocode:
double randomDirection = Math.random();
if (direction > 0.25) {
// move left if possible
} else if (direction > 0.5) {
// move right if possible
} else if (direction > 0.75) {
// move down if possible
} else {
// move up if possible
}

for-each loop in Java for different objects

i created a pacman game with everything in it but the problem is that the ghosts and their animation require a lot of code.
example:
every ghost needs 3 if statements at the moment that is 20 lines of code per ghost and if i have 3 ghosts in the game that is 3 x 20 = 60 lines of useless coding..
with my php experience i would say.. use a foreach loop or something similar.. but how should i do this in Java? can someone give me an example? the way i do it now is published below:
creating ghost objects;
DrawPacMan ghost1 = new DrawPacMan();
DrawPacMan ghost2 = new DrawPacMan();
and the painting goes like:
int g1x = 0;
boolean g1r = true;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// pacman movement
diameter = 75;
pacman.drawPacMan(g, getHorPlaats(), getVerPlaats(), diameter, getView(), Color.yellow);
// ghosts movement
if(g1r == true) {
g1x += ghostSpeed;
}
if(g1r == false) {
g1x -= ghostSpeed;
}
if(g1x == 500 || g1x == 0) {
g1r = !g1r;
}
System.out.println(g1r);
ghost1.drawGhost(g, g1x, 40, diameter, Color.red);
ghost2.drawGhost(g, 170, 70, diameter, Color.blue);
}
It looks to me like you're not approaching this in a object-oriented fashion. Why not use a collection of ghosts eg. List<Ghost> and define a Ghost object with it's location, colour etc?
This line:
ghost1.drawGhost(g, g1x, 40, diameter, Color.red);
would then be replace with
ghost.draw(g);
and you'd iterate through the list, calling draw() for each.
for(Ghost ghost : ghosts) {
ghost.draw(g); // pass in the graphics context
}
Each ghost knows it's location, colour, state etc. and you can create as many as you like:
List<Ghost> ghosts = new ArrayList<Ghost>();
for (int i = 0; i < 10; i++) {
ghosts.add(new Ghost());
}
Since you seem to be new to Java and still getting to know the best idioms, I'll advise on something that is not directly an answer to your question, but is so in a more general sense. Your code
if(g1r == true) {
g1x += ghostSpeed;
}
if(g1r == false) {
g1x -= ghostSpeed;
}
can be rewritten as just
g1x += ghostSpeed * (g1r? 1 : -1);
A general note: never compare booleans to literal values. b == true is the same as just b and b == false is the same as !b.
This code
if (g1x == 500 || g1x == 0) {
g1r = !g1r;
}
will probably result in a bug at runtime as you don't precede it with fencing-in code: g1x can easily step over your limits. You should write instead
if (g1x >= 500) { g1x = 500; g1r = false; }
else if (g1x <= 0) { g1x = 0; g1r = true; }
Pass the ghost object as another parameter in the same function paintComponent(Graphics g, Ghost gr)
You can make the conditional statements inline, e.g. g1r == true ? g1x += ghostSpeed : g1x -= ghostSpeed

Categories

Resources