diff --git a/Balloon.pde b/Balloon.pde new file mode 100644 index 0000000..bb2c6b8 --- /dev/null +++ b/Balloon.pde @@ -0,0 +1,85 @@ +class Balloon { + float x; + float y; + float z; + float radius; + float angle; + PVector velocity; + PVector acceleration; + float lastWindChangeTime; + + Balloon(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + this.radius = 50; + this.velocity = new PVector(0, 0, 0); + this.acceleration = new PVector(0, 0, 0); + this.angle = 0; + } + + void applyForce(PVector force) { + acceleration.add(force); + } + + void applyBuoyancy() { + PVector buoyantForce = new PVector(0, 0, buoyancy); + applyForce(buoyantForce); + } + + void applyDamping() { + PVector dampingForce = velocity.copy().mult(-damping); + applyForce(dampingForce); + } + + void draw() { + pushMatrix(); + + if (millis() - lastWindChangeTime > windChangeInterval) { + wind = PVector.random3D(); + wind.mult(20); + lastWindChangeTime = millis(); + } + + rotateX(HALF_PI); + + z += 2; + + translate(x, y, z); + + fill(255, 0, 0); + noStroke(); + sphere(radius); + stroke(1); + + drawLeg(-radius / 2, -radius / 2); + drawLeg(radius / 2, -radius / 2); + drawLeg(-radius / 2, radius / 2); + drawLeg(radius / 2, radius / 2); + + translate(0, 0, -75); + box(70, 70, 25); + + applyBuoyancy(); + applyDamping(); + + velocity.add(acceleration); + x += velocity.x; + y += velocity.y; + z += velocity.z; + + acceleration.mult(0); + angle += 0.01; + + popMatrix(); + } + + void drawLeg(float x, float y) { + pushMatrix(); + int legHeight = 80; + translate(x, y, -legHeight / 2); + fill(yellow); + box(5, 5, legHeight); + popMatrix(); + } +} diff --git a/Bird.pde b/Bird.pde new file mode 100644 index 0000000..152e214 --- /dev/null +++ b/Bird.pde @@ -0,0 +1,308 @@ +class Bird extends FlyingCreature { + float x; + float y; + float z; + float hp; + float goBackX, goBackY, goBackZ; + float wingAngle = PI; + int wingDirection = 1; + float wingFlapSpeed = 0.05; + float wingFlapRange = QUARTER_PI; + float perlinOffsetX; + float perlinOffsetY; + float perlinOffsetZ; + float actualOffset = 1; + boolean isCatching = false; + boolean needToGoBack = false; + Butterfly butterfly = null; + color fillcolor = color(0, 0, 0); + + Bird(float x, float y, float z) { + super(x, y, z); + this.perlinOffsetX = random(1000); + this.perlinOffsetY = random(1000); + this.perlinOffsetZ = random(1000); + } + + void catchButterfly() { + ArrayList < Butterfly > availableButterflies = new ArrayList < > (); + for (Butterfly butterfly: terra.butterflies) { + if (!butterfly.isBeingCaught) { + availableButterflies.add(butterfly); + } + } + + if (!availableButterflies.isEmpty()) { + int randomIndex = (int) random(availableButterflies.size()); + + Butterfly randomButterfly = availableButterflies.get(randomIndex); + + butterfly = randomButterfly; + isCatching = true; + fillcolor = color(255, 255, 255); + + randomButterfly.isBeingCaught = true; + goBackX = x; + goBackY = y; + goBackZ = z; + } + + } + + void uncatchButterfly() { + terra.butterflies.remove(butterfly); + terra.addButterfly(); + butterfly = null; + isCatching = false; + needToGoBack = true; + fillcolor = color(0, 0, 0); + hp = 100; + } + + void tryGoBack() { + this.hp -= 0.1; + pushMatrix(); + rotateX(HALF_PI); + + if (dist(x, y, z, goBackX, goBackY, goBackZ) > 10) { + int speed = 5; + float dirX = goBackX - x; + float dirY = goBackY - y; + float dirZ = goBackZ - z; + + float magnitude = sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); + dirX /= magnitude; + dirY /= magnitude; + dirZ /= magnitude; + + x += dirX * speed; + y += dirY * speed; + z += dirZ * speed; + } else { + popMatrix(); + needToGoBack = false; + return; + } + + translate(x, y, z); + + translate(0, 0, 20); + float colorValue = map(hp, 0, 100, 0, 1); + colorValue = constrain(colorValue, 0, 1); + + color boxColor = lerpColor(color(255, 0, 0), color(0, 255, 0), colorValue); + fill(boxColor); + rotateX(HALF_PI); + rotateZ(PI); + translate(-hp/2, -10, 0); + text("Not catching!", 0, 0); + translate(0, -10, 0); + text("HP: " + nf(hp, 0, 2), 0, 0); + translate(hp/2, 20, 0); + rotateZ(-PI); + rotateX(-HALF_PI); + rotateZ(HALF_PI); + translate(0, 0, 0); + box(2, hp, 2); + rotateZ(-HALF_PI); + translate(0, 0, 0); + + translate(0, 0, -20); + + fill(fillcolor); + box(10, 10, 10); + + translate(-6, 3, 5); + box(6, 6, 6); + + translate(6, -3, -5); + translate(0, -5, 5); + + float wingFlap = sin(wingAngle) * wingFlapRange; + rotateX(wingFlap); + + wingDirection = (wingAngle >= PI + wingFlapRange || wingAngle <= PI - wingFlapRange) ? -wingDirection : wingDirection; + + wingAngle += wingDirection * wingFlapSpeed; + + fill(fillcolor); + drawWing(10, 30); + + rotateX(-wingFlap); + translate(5, 5); + rotateZ(HALF_PI); + + rotateX(wingFlap); + + drawWing(10, 30); + + popMatrix(); + } + + @Override + void draw() { + this.hp -= 0.1; + + if (!isCatching && random(1) < 0.01) { + catchButterfly(); + } + + if (needToGoBack) { + tryGoBack(); + return; + } + + if (!isCatching) { + pushMatrix(); + rotateX(HALF_PI); + + translate(x, y, z); + + translate(0, 0, 20); + float colorValue = map(hp, 0, 100, 0, 1); + colorValue = constrain(colorValue, 0, 1); + + color boxColor = lerpColor(color(255, 0, 0), color(0, 255, 0), colorValue); + fill(boxColor); + rotateX(HALF_PI); + rotateZ(PI); + translate(-hp/2, -10, 0); + text("Not catching!", 0, 0); + translate(0, -10, 0); + text("HP: " + nf(hp, 0, 2), 0, 0); + translate(hp/2, 20, 0); + rotateZ(-PI); + rotateX(-HALF_PI); + rotateZ(HALF_PI); + translate(0, 0, 0); + box(2, hp, 2); + rotateZ(-HALF_PI); + translate(0, 0, 0); + + translate(0, 0, -20); + + actualOffset += 10; + + z = map(noise(perlinOffsetX, actualOffset * 0.0002), 0, 1, 600, 1200); + x = map(noise(perlinOffsetY, actualOffset * 0.0001), 0, 1, 0, terrainLength * cubeWidth); + y = map(noise(perlinOffsetZ, actualOffset * 0.0001), 0, 1, 0, terrainWidth * cubeWidth); + + fill(fillcolor); + box(10, 10, 10); + + translate(-6, 3, 5); + box(6, 6, 6); + + translate(6, -3, -5); + translate(0, -5, 5); + + float wingFlap = sin(wingAngle) * wingFlapRange; + rotateX(wingFlap); + + wingDirection = (wingAngle >= PI + wingFlapRange || wingAngle <= PI - wingFlapRange) ? -wingDirection : wingDirection; + + wingAngle += wingDirection * wingFlapSpeed; + + fill(fillcolor); + drawWing(10, 30); + + rotateX(-wingFlap); + translate(5, 5); + rotateZ(HALF_PI); + + rotateX(wingFlap); + + drawWing(10, 30); + + popMatrix(); + + } else { + this.hp -= 0.1; + pushMatrix(); + rotateX(HALF_PI); + + float dirX = butterfly.x - x; + float dirY = butterfly.y - y; + float dirZ = butterfly.z - z; + + float magnitude = sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); + dirX /= magnitude; + dirY /= magnitude; + dirZ /= magnitude; + + float speed = 4.0; + + x += dirX * speed; + y += dirY * speed; + z += dirZ * speed; + + translate(x, y, z); + + translate(0, 0, 20); + float colorValue = map(hp, 0, 100, 0, 1); + colorValue = constrain(colorValue, 0, 1); + + color boxColor = lerpColor(color(255, 0, 0), color(0, 255, 0), colorValue); + fill(boxColor); + rotateX(HALF_PI); + rotateZ(PI); + translate(-hp/2, -10, 0); + text("Catching!", 0, 0); + translate(0, -10, 0); + text("HP: " + nf(hp, 0, 2), 0, 0); + translate(hp/2, 20, 0); + rotateZ(-PI); + rotateX(-HALF_PI); + rotateZ(HALF_PI); + translate(0, 0, 0); + box(2, hp, 2); + rotateZ(-HALF_PI); + translate(0, 0, 0); + + translate(0, 0, -20); + + fill(fillcolor); + box(10, 10, 10); + + translate(-6, 3, 5); + box(6, 6, 6); + + translate(6, -3, -5); + translate(0, -5, 5); + + float wingFlap = sin(wingAngle) * wingFlapRange; + rotateX(wingFlap); + + wingDirection = (wingAngle >= PI + wingFlapRange || wingAngle <= PI - wingFlapRange) ? -wingDirection : wingDirection; + + wingAngle += wingDirection * wingFlapSpeed; + + fill(fillcolor); + drawWing(10, 30); + + rotateX(-wingFlap); + translate(5, 5); + + rotateZ(HALF_PI); + rotateX(wingFlap); + + drawWing(10, 30); + + if (dist(x, y, z, butterfly.x, butterfly.y, butterfly.z) < 20) uncatchButterfly(); + + popMatrix(); + } + + if (hp < 0) hp = 100; + } + + @Override + void drawWing(float width, float length) { + beginShape(); + vertex(-width / 2, 0); + vertex(width / 2, 0); + vertex(width / 4, -length); + vertex(-width / 4, -length); + endShape(CLOSE); + } +} diff --git a/Block.pde b/Block.pde new file mode 100644 index 0000000..986007f --- /dev/null +++ b/Block.pde @@ -0,0 +1,16 @@ +class Block { + int x; + int y; + float h; + boolean isTree; + boolean isFlower; + int treeSize; + color treeColor; + Block(int x, int y, float h, color treeColor, int treeSize) { + this.x = x; + this.y = y; + this.h = h; + this.treeColor = treeColor; + this.treeSize = treeSize; + } +} diff --git a/Butterfly.pde b/Butterfly.pde new file mode 100644 index 0000000..d3172b1 --- /dev/null +++ b/Butterfly.pde @@ -0,0 +1,67 @@ +class Butterfly { + float x; + float y; + float z; + float wingAngle = PI; + int wingDirection = 1; + float wingFlapSpeed = 0.05; + float wingFlapRange = QUARTER_PI; + float perlinOffsetX; + float perlinOffsetY; + float perlinOffsetZ; + boolean isBeingCaught = false; + + Butterfly(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + this.perlinOffsetX = random(1000); + this.perlinOffsetY = random(1000); + this.perlinOffsetZ = random(1000); + } + + void draw() { + pushMatrix(); + rotateX(HALF_PI); + + z = map(noise(perlinOffsetX, millis() * 0.0002), 0, 1, 400, 600); + x = map(noise(perlinOffsetY, millis() * 0.0001), 0, 1, 0, terrainLength * cubeWidth); + y = map(noise(perlinOffsetZ, millis() * 0.0001), 0, 1, 0, terrainWidth * cubeWidth); + + fill(0, 191, 255); + translate(x, y, z); + box(3, 3, 3); + translate(-1, 1, 2); + box(2, 2, 2); + translate(1, -2, -1); + + float wingFlap = sin(wingAngle) * wingFlapRange; + rotateX(wingFlap); + + wingDirection = (wingAngle >= PI + wingFlapRange || wingAngle <= PI - wingFlapRange) ? -wingDirection : wingDirection; + + wingAngle += wingDirection * wingFlapSpeed; + + fill(0, 191, 255); + drawWing(3, 5); + + rotateX(-wingFlap); + translate(1, 1); + rotateZ(HALF_PI); + + rotateX(wingFlap); + + fill(0, 191, 255); + drawWing(3, 5); + popMatrix(); + } + + void drawWing(float width, float length) { + beginShape(); + vertex(-width / 2, 0); + vertex(width / 2, 0); + vertex(width / 4, -length); + vertex(-width / 4, -length); + endShape(CLOSE); + } +} diff --git a/Colors.pde b/Colors.pde new file mode 100644 index 0000000..ac56210 --- /dev/null +++ b/Colors.pde @@ -0,0 +1,12 @@ +color yellow = color(255, 255, 0); +color green = color(0, 255, 0); +color blue = color(0, 0, 255); +color red = color(255, 0, 0); +color darkgreen = color(0, 100, 0); +color autumn1 = color(183, 65, 14); +color autumn2 = color(204, 85, 0); +color autumn3 = color(255, 215, 0); +color autumn4 = color(255, 204, 0); +color autumn5 = color(139, 69, 19); +color autumn6 = color(101, 67, 33); +color autumn7 = color(107, 142, 35); diff --git a/Config.pde b/Config.pde new file mode 100644 index 0000000..16f293f --- /dev/null +++ b/Config.pde @@ -0,0 +1,27 @@ +int terrainLength = 1000; +int terrainWidth = 1000; + +int minTreeHeight = 20; +int maxTreeHeight = 70; + +float noiseStep = 0.02; +float noiseScale = 5; +long randomSeedValue = 55; +long noiseSeedValue = 254; +int noiseOctaves = 4; +float noiseFalloff = 0.5; + +int cubeWidth = 20; +int cubeLength = 20; +float cubeSize = 100; + +float camSpeed = 20; +float sensitivity = 0.01; +float pitch = 0; +float yaw = 0; +int farPlaneDistance = 4000; + +float maxForce = 0.1; +float buoyancy = -0.02; +float damping = 0.995; +float windChangeInterval = 3000; diff --git a/FlyingCreature.pde b/FlyingCreature.pde new file mode 100644 index 0000000..29a5fbe --- /dev/null +++ b/FlyingCreature.pde @@ -0,0 +1,273 @@ +abstract class FlyingCreature { + float x; + float y; + float z; + float hp; + float goBackX, goBackY, goBackZ; + float wingAngle = PI; + int wingDirection = 1; + float wingFlapSpeed = 0.05; + float wingFlapRange = QUARTER_PI; + float perlinOffsetX; + float perlinOffsetY; + float perlinOffsetZ; + float actualOffset = 1; + boolean isCatching = false; + boolean needToGoBack = false; + Butterfly butterfly = null; + color fillcolor = color(0, 0, 0); + + FlyingCreature(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + this.perlinOffsetX = random(1000); + this.perlinOffsetY = random(1000); + this.perlinOffsetZ = random(1000); + } + + void catchButterfly() { + ArrayList < Butterfly > availableButterflies = new ArrayList < > (); + for (Butterfly butterfly: terra.butterflies) { + if (!butterfly.isBeingCaught) { + availableButterflies.add(butterfly); + } + } + + if (!availableButterflies.isEmpty()) { + int randomIndex = (int) random(availableButterflies.size()); + + Butterfly randomButterfly = availableButterflies.get(randomIndex); + + butterfly = randomButterfly; + isCatching = true; + fillcolor = color(255, 255, 255); + + randomButterfly.isBeingCaught = true; + goBackX = x; + goBackY = y; + goBackZ = z; + } + + } + + void uncatchButterfly() { + terra.butterflies.remove(butterfly); + terra.addButterfly(); + butterfly = null; + isCatching = false; + needToGoBack = true; + fillcolor = color(0, 0, 0); + hp = 100; + } + + void tryGoBack() { + this.hp -= 0.1; + pushMatrix(); + rotateX(HALF_PI); + + if (dist(x, y, z, goBackX, goBackY, goBackZ) > 10) { + int speed = 5; + float dirX = goBackX - x; + float dirY = goBackY - y; + float dirZ = goBackZ - z; + + // Normalize the direction vector + float magnitude = sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); + dirX /= magnitude; + dirY /= magnitude; + dirZ /= magnitude; + + x += dirX * speed; + y += dirY * speed; + z += dirZ * speed; + } else { + popMatrix(); + needToGoBack = false; + x = goBackX; + y = goBackY; + z = goBackZ; + return; + } + + translate(x, y, z); + + translate(0, 0, 20); + float colorValue = map(hp, 0, 100, 0, 1); + colorValue = constrain(colorValue, 0, 1); + + color boxColor = lerpColor(color(255, 0, 0), color(0, 255, 0), colorValue); + fill(boxColor); + box(2, hp / 10, 2); + + translate(0, 0, -20); + + fill(fillcolor); + box(10, 10, 10); + + translate(-6, 3, 5); + box(6, 6, 6); + + translate(6, -3, -5); + translate(0, -5, 5); + + float wingFlap = sin(wingAngle) * wingFlapRange; + rotateX(wingFlap); + + wingDirection = (wingAngle >= PI + wingFlapRange || wingAngle <= PI - wingFlapRange) ? -wingDirection : wingDirection; + + wingAngle += wingDirection * wingFlapSpeed; + + fill(fillcolor); + drawWing(10, 30); + + rotateX(-wingFlap); + translate(5, 5); + rotateZ(HALF_PI); + + rotateX(wingFlap); + + drawWing(10, 30); + + popMatrix(); + } + + void draw() { + this.hp -= 0.1; + + if (!isCatching && random(1) < 0.01) { + catchButterfly(); + } + + if (needToGoBack) { + tryGoBack(); + return; + } + + if (!isCatching) { + pushMatrix(); + rotateX(HALF_PI); + + translate(x, y, z); + + translate(0, 0, 20); + float colorValue = map(hp, 0, 100, 0, 1); + colorValue = constrain(colorValue, 0, 1); + + color boxColor = lerpColor(color(255, 0, 0), color(0, 255, 0), colorValue); + fill(boxColor); + box(2, hp / 10, 2); + + translate(0, 0, -20); + + actualOffset += 10; + + z = map(noise(perlinOffsetX, actualOffset * 0.0002), 0, 1, 600, 1200); + x = map(noise(perlinOffsetY, actualOffset * 0.0001), 0, 1, 0, terrainLength * cubeWidth); + y = map(noise(perlinOffsetZ, actualOffset * 0.0001), 0, 1, 0, terrainWidth * cubeWidth); + + fill(fillcolor); + box(10, 10, 10); + + translate(-6, 3, 5); + box(6, 6, 6); + + translate(6, -3, -5); + translate(0, -5, 5); + + float wingFlap = sin(wingAngle) * wingFlapRange; + rotateX(wingFlap); + + wingDirection = (wingAngle >= PI + wingFlapRange || wingAngle <= PI - wingFlapRange) ? -wingDirection : wingDirection; + + wingAngle += wingDirection * wingFlapSpeed; + + fill(fillcolor); + drawWing(10, 30); + + rotateX(-wingFlap); + translate(5, 5); + rotateZ(HALF_PI); + + rotateX(wingFlap); + + drawWing(10, 30); + + popMatrix(); + + } else { + this.hp -= 0.1; + pushMatrix(); + rotateX(HALF_PI); + + float dirX = butterfly.x - x; + float dirY = butterfly.y - y; + float dirZ = butterfly.z - z; + + float magnitude = sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ); + dirX /= magnitude; + dirY /= magnitude; + dirZ /= magnitude; + + float speed = 4.0; + + x += dirX * speed; + y += dirY * speed; + z += dirZ * speed; + + translate(x, y, z); + + translate(0, 0, 20); + float colorValue = map(hp, 0, 100, 0, 1); + colorValue = constrain(colorValue, 0, 1); + + color boxColor = lerpColor(color(255, 0, 0), color(0, 255, 0), colorValue); + fill(boxColor); + box(2, hp / 10, 2); + + translate(0, 0, -20); + + fill(fillcolor); + box(10, 10, 10); + + translate(-6, 3, 5); + box(6, 6, 6); + + translate(6, -3, -5); + translate(0, -5, 5); + + float wingFlap = sin(wingAngle) * wingFlapRange; + rotateX(wingFlap); + + wingDirection = (wingAngle >= PI + wingFlapRange || wingAngle <= PI - wingFlapRange) ? -wingDirection : wingDirection; + + wingAngle += wingDirection * wingFlapSpeed; + + fill(fillcolor); + drawWing(10, 30); + + rotateX(-wingFlap); + translate(5, 5); + + rotateZ(HALF_PI); + rotateX(wingFlap); + + drawWing(10, 30); + + if (dist(x, y, z, butterfly.x, butterfly.y, butterfly.z) < 20) uncatchButterfly(); + + popMatrix(); + } + + if (hp < 0) hp = 100; + } + + void drawWing(float width, float length) { + beginShape(); + vertex(-width / 2, 0); + vertex(width / 2, 0); + vertex(width / 4, -length); + vertex(-width / 4, -length); + endShape(CLOSE); + } +} diff --git a/Main.pde b/Main.pde new file mode 100644 index 0000000..28a2e11 --- /dev/null +++ b/Main.pde @@ -0,0 +1,77 @@ +PVector camPosition = new PVector(1000, -700, 700); +PVector lookAt = new PVector(0, 0, -1); +PVector wind = new PVector(5, -8, 0); +Terrain terra = new Terrain(); +Balloon balloon = new Balloon(50 * 20, 50 * 20, 20 * 20); + +void setup() { + fullScreen(P3D); + frameRate(144); + //size(800, 600, P3D); + + randomSeed(randomSeedValue); + noiseSeed(noiseSeedValue); + noiseDetail(noiseOctaves, noiseFalloff); + + terra.setup(); + terra.reloadTrees(); +} + +void keyPressed() { + if (keyCode == UP) { + noiseScale += 0.25; + terra.reloadTrees(); + } else if (keyCode == DOWN) { + noiseScale -= 0.25; + terra.reloadTrees(); + } +} + +void draw() { + background(173, 216, 230); + lights(); + + yaw += -1 * sensitivity * (mouseX - pmouseX); + pitch += sensitivity * (mouseY - pmouseY); + + pitch = constrain(pitch, -HALF_PI + 0.01, HALF_PI - 0.01); + + float cosPitch = cos(pitch); + float sinPitch = sin(pitch); + float cosYaw = cos(yaw); + float sinYaw = sin(yaw); + + lookAt.x = sinYaw * cosPitch; + lookAt.y = sinPitch; + lookAt.z = cosYaw * cosPitch; + + if (keyPressed) { + if (key == 'g') terra.applyGravity(); + + if (key == 'w') camPosition.add(PVector.mult(lookAt, camSpeed)); + + if (key == 's') camPosition.sub(PVector.mult(lookAt, camSpeed)); + + if (key == 'a') { + PVector left = lookAt.cross(new PVector(0, -1, 0)); + camPosition.add(PVector.mult(left, camSpeed)); + } + + if (key == 'd') { + PVector right = lookAt.cross(new PVector(0, -1, 0)); + camPosition.sub(PVector.mult(right, camSpeed)); + } + + if (key == 'r') terra.blocks.get(0).x += 1; + if (key == 'f') terra.blocks.get(0).y += 1; + } + + camera(camPosition.x, camPosition.y, camPosition.z, camPosition.x + lookAt.x, camPosition.y + lookAt.y, camPosition.z + lookAt.z, 0, 1, 0); + perspective(PI / 3.0, float(width) / float(height), 1, farPlaneDistance); + + terra.drawTerrain(camPosition); + + PVector windForce = wind.copy().mult(0.1); + balloon.applyForce(windForce); + balloon.draw(); +} diff --git a/Terrain.pde b/Terrain.pde new file mode 100644 index 0000000..031bc2d --- /dev/null +++ b/Terrain.pde @@ -0,0 +1,142 @@ +class Terrain { + ArrayList < Block > blocks = new ArrayList < > (); + ArrayList < Bird > birds = new ArrayList < > (); + ArrayList < Butterfly > butterflies = new ArrayList < > (); + float blue = 100; + float bluedirection = -0.25; + + void addButterfly() { + if (butterflies.size() < 10) + butterflies.add(new Butterfly(int(random(1, terrainWidth)) * cubeWidth, int(random(1, terrainLength)) * cubeWidth, 100)); + } + + void addBird() { + if (birds.size() < 10) + birds.add(new Bird(int(random(1, terrainWidth)) * cubeWidth, int(random(1, terrainLength)) * cubeWidth, 1200)); + } + + void generateTerrain() { + for (int i = 0; i < terrainWidth; i++) { + for (int j = 0; j < terrainLength; j++) { + Block block = new Block(i, j, noise(noiseStep * i, noiseStep * j), getRandomTreeColor(), int(random(minTreeHeight + 30, maxTreeHeight))); + blocks.add(block); + if (random(0, 1) < 0.001) addBird(); + if (random(0, 1) < 0.001) addButterfly(); + } + } + } + + void reloadTrees() { + blocks.forEach(block -> { + if ((noiseScale * block.h * cubeSize) > 170) { + if (int(random(0, 101)) < 1) { + block.isTree = true; + block.treeColor = getRandomTreeColor(); + } else + block.isTree = false; + } else + block.isTree = false; + + if (!block.isTree && (noiseScale * block.h * cubeSize) > 170) { + if (int(random(0, 101)) < 1) { + block.isFlower = true; + block.treeColor = getRandomFlowerColor(); + } else + block.isFlower = false; + } else + block.isFlower = false; + }); + } + + void setup() { + generateTerrain(); + reloadTrees(); + } + + void drawTerrain(PVector position) { + blocks.forEach(block -> { + float blockHeight = noiseScale * block.h * cubeSize; + + if (blockHeight < 150) { + fill(0, 0, int(blue)); + if (blue > 220) bluedirection = -0.15; + if (blue < 190) bluedirection = 0.15; + blue += bluedirection; + blockHeight = 135 + blue / 20; + } else if (blockHeight > 150 && blockHeight < 170) { + fill(yellow); + } else if (blockHeight > 350) { + blockHeight *= 1.5; + fill(255, 255, 255); + } else { + fill(green); + } + + float posX = block.x * cubeWidth; + float posY = block.y * cubeLength; + float posZ = blockHeight / 2.0; + + if (dist(posX, 0.0, posY, position.x, 0.0, position.z) > 1500) return; + + pushMatrix(); + + rotateX(HALF_PI); + translate(posX, posY, posZ); + box(cubeWidth, cubeLength, blockHeight); + + if (block.isTree && blockHeight < 350) drawNormalTree(block, posZ); + else if (block.isTree) drawPineTree(block, posZ); + +else if (block.isFlower && blockHeight < 350) drawFlower(block, posZ); + + popMatrix(); + }); + + birds.forEach(bird -> bird.draw()); + butterflies.forEach(butterfly -> butterfly.draw()); + } + + void applyGravity() { + float gravity = 0.001; + blocks.forEach(block -> { + block.h -= gravity; + if (noiseScale * block.h * cubeSize < 170) { + block.isTree = false; + block.isFlower = false; + } + }); + } + + void drawNormalTree(Block block, float posZ) { + fill(222, 184, 135); + translate(0, 0, posZ + 50); + box(cubeWidth, cubeLength, 100); + translate(0, 0, 50); + fill(block.treeColor); + noStroke(); + sphere(block.treeSize); + stroke(1); + } + + void drawPineTree(Block block, float posZ) { + fill(222, 184, 135); + translate(0, 0, posZ + 50); + box(cubeWidth, cubeLength, 100); + translate(0, 0, 50); + fill(0, 100, 0); + noStroke(); + cylinder(50, 1, 100, 50); + stroke(1); + } + + void drawFlower(Block block, float posZ) { + fill(0, 200, 0); + translate(0, 0, posZ + 10); + box(5, 5, 20); + translate(0, 0, 10); + fill(block.treeColor); + noStroke(); + sphere(10); + stroke(1); + } +} diff --git a/Utils.pde b/Utils.pde new file mode 100644 index 0000000..620597a --- /dev/null +++ b/Utils.pde @@ -0,0 +1,86 @@ +void cylinder(float bottom, float top, float h, int sides) { + pushMatrix(); + float angleX = HALF_PI; + float angleY = 0; + rotateX(angleX); + rotateY(angleY); + translate(0, h / 2, 0); + + float angle; + float[] x = new float[sides + 1]; + float[] z = new float[sides + 1]; + + float[] x2 = new float[sides + 1]; + float[] z2 = new float[sides + 1]; + + for (int i = 0; i < x.length; i++) { + angle = TWO_PI / (sides) * i; + x[i] = sin(angle) * bottom; + z[i] = cos(angle) * bottom; + } + + for (int i = 0; i < x.length; i++) { + angle = TWO_PI / (sides) * i; + x2[i] = sin(angle) * top; + z2[i] = cos(angle) * top; + } + + beginShape(TRIANGLE_FAN); + + vertex(0, -h / 2, 0); + + for (int i = 0; i < x.length; i++) { + vertex(x[i], -h / 2, z[i]); + } + + endShape(); + + beginShape(QUAD_STRIP); + + for (int i = 0; i < x.length; i++) { + vertex(x[i], -h / 2, z[i]); + vertex(x2[i], h / 2, z2[i]); + } + + endShape(); + + beginShape(TRIANGLE_FAN); + + vertex(0, h / 2, 0); + + for (int i = 0; i < x.length; i++) { + vertex(x2[i], h / 2, z2[i]); + } + + endShape(); + + popMatrix(); +} + +color getRandomTreeColor() { + int rand = int(random(0, 101)); + + if (rand < 10) return color(255, 69, 0); + if (rand < 20) return autumn1; + if (rand < 30) return autumn2; + if (rand < 40) return autumn3; + if (rand < 50) return autumn4; + if (rand < 60) return autumn5; + if (rand < 70) return autumn6; + if (rand < 80) return autumn7; + + return darkgreen; +} + +color getRandomFlowerColor() { + //float yellowBrightness = 150; + //float rand1 = yellowBrightness + randomGaussian() * 25; + //float rand2 = yellowBrightness + randomGaussian() * 25; + //float rand3 = yellowBrightness + randomGaussian() * 25; + + //rand1 = constrain(rand1, 0, 255); + //rand2 = constrain(rand2, 0, 255); + //rand3 = constrain(rand3, 0, 255); + + return color(random(0, 255), random(0, 255), random(0, 255)); +}