It was fun to figure out how to create a whole landscape without having to define absolutely everything and making it more interesting with randomness. I added a shooting star with a very small creation probability to create a little surprise within the landscape every once in a while.
// Rachel Legg / rlegg / Section C
//have trees and stars move by
//every once in a while, a surprising shooting star
//car in the middle (moving past trees)
var stars = [];
var trees = [];
var shootingStars = [];
var car;
function preload(){
car = loadImage("https://i.imgur.com/C7SXV3W.png");
}
function setup() {
createCanvas(450, 300);
frameRate(10);
//initial stars and trees
for(var i = 0; i < 6; i++){
var sx = random(width);
stars[i] = makeStar(sx);
}
for(var i = 0; i < 10; i++){
var sx = random(width);
trees[i] = makeTree(sx);
}
//random shooting star
for(var i = 0; i < 1; i++){
var sx = random(width);
shootingStars[i] = makeShootingStar(sx);
}
}
function draw() {
//sky - dark blue
background(10, 52, 99);
//ground
fill("darkgreen");
noStroke();
rect(0, 240, 500, 75);
//road
fill("gray");
rect(0, 260, 495, 10)
updateAndDisplayStar();
removeStarOutOfView();
addNewStar();
updateAndDisplayShootingStars();
removeShootingStarOutOfView();
addNewShootingStars();
updateAndDisplayTree();
removeTreeOutOfView();
addNewTree();
//car stays stationary as scenery moves by
//drew out car in illustrator & uploaded to imgur
image(car, width/2 - 60, 207, 165, 65);
}
//stars object
function makeStar(starLocationX){
var star = {x : starLocationX,
y : random(0, 170),
starScale : random(0.1, 0.5),
speed : -1,
move : moveStar,
display : displayStar}
return star;
}
function displayStar(){
push();
translate(this.x, this.y);
fill(255);
noStroke();
scale(this.starScale);
beginShape();
vertex(50, 18);
vertex(61, 37);
vertex(83, 43);
vertex(69, 60);
vertex(71, 82);
vertex(50, 73);
vertex(29, 82);
vertex(31, 60);
vertex(17, 43);
vertex(39, 37);
endShape();
pop();
}
//update star positions and display
function updateAndDisplayStar(){
for(var i = 0; i < stars.length; i++){
stars[i].move();
stars[i].display();
}
}
function addNewStar(){
var newStarProbability = 0.01;
if (random(0, 1) < newStarProbability){
stars.push(makeStar(width));
}
}
function removeStarOutOfView (){
//if star goes off left edge, remove from array
var starsToKeep = [];
for (var i = 0; i < stars.length; i++){
if (stars[i].x + 50 > 0) {
starsToKeep.push(stars[i]);
}
}
//stars left
stars = starsToKeep;
}
function moveStar(){
this.x += this.speed;
}
//trees object
function makeTree(treeLocationX){
var tree = {xt : treeLocationX,
yt : 240,
treeScale : random(0.1, 0.5),
treeColor : color(0, random(75, 255), 0),
speedT : -3,
moveT : moveTree,
displayT : displayTree}
return tree;
}
function displayTree(){
push();
translate(this.xt + 60, this.yt); //add 60 so transitions onto screen
fill(255);
noStroke();
scale(this.treeScale);
//tree!
noStroke();
fill("brown");
rect(0, 0, 10, -50);
rect(1, 0, -10, -50);
fill(this.treeColor);
triangle(-60, -50, 60, -50, 0, -400);
pop();
}
//update tree positions and display
function updateAndDisplayTree(){
for(var i = 0; i < trees.length; i++){
trees[i].moveT();
trees[i].displayT();
}
}
function addNewTree(){
var newTreeProbability = 0.04;
if (random(0, 1) < newTreeProbability){
trees.push(makeTree(width));
}
}
function removeTreeOutOfView (){
//if star goes off left edge, remove from array
var treesToKeep = [];
for (var i = 0; i < trees.length; i++){
if (trees[i].xt + 100 > 0) {
treesToKeep.push(trees[i]);
}
}
//trees left
trees = treesToKeep;
}
function moveTree(){
this.xt += this.speedT;
}
//shooting star object
function makeShootingStar(locationX){
var shootingStar = {xs : locationX,
ys : random(75, 125),
shootingStarScale : random(0.1, 0.3),
speedS : -8,
moveS : moveShootingStar,
displayS : displayShootingStar}
return shootingStar;
}
function displayShootingStar(){
push();
translate(this.xs + 60, this.ys); //add 60 so transitions onto screen
fill("yellow");
noStroke();
scale(this.shootingStarScale);
//shooting star
beginShape();
vertex(50, 18);
vertex(61, 37);
vertex(83, 43);
vertex(69, 60);
vertex(71, 82);
vertex(50, 73);
vertex(29, 82);
vertex(31, 60);
vertex(17, 43);
vertex(39, 37);
endShape();
stroke("yellow");
strokeWeight(2);
line(60, 37, 100, 37);
line(60, 47, 110, 47);
line(60, 57, 120, 57);
pop();
}
//update tree positions and display
function updateAndDisplayShootingStars(){
for(var i = 0; i < shootingStars.length; i++){
shootingStars[i].moveS();
shootingStars[i].displayS();
}
}
function addNewShootingStars(){
var newShootingStarsProbability = 0.008;
if (random(0, 1) < newShootingStarsProbability){
shootingStars.push(makeShootingStar(width));
}
}
function removeShootingStarOutOfView (){
//if star goes off left edge, remove from array
var shootingStarsToKeep = [];
for (var i = 0; i < shootingStars.length; i++){
if (shootingStars[i].xs + 100 > 0) {
shootingStarsToKeep.push(shootingStars[i]);
}
}
//trees left
shootingStars = shootingStarsToKeep;
}
function moveShootingStar(){
this.xs += this.speedS;
}
/* Evan Stuhlfire
* estuhlfi@andrew.cmu.edu section B
* project-11-generative landscape */
var hills = [];
var trees = [];
var chickArray = [];
var imgArray = [];
var farm = [];
var barnImg;
var cowImg;
var planeObj;
var flyingPlane = false;
var scrollSpeed = 5;
function preload(){
// preload images
// URLs to imgur walking chick
// Chick image licensed from Adobe stock images
var filenames = [];
filenames[0] = "https://i.imgur.com/kjBGzBF.png";
filenames[1] = "https://i.imgur.com/hxvbkWZ.png";
filenames[2] = "https://i.imgur.com/53MK7g1.png";
filenames[3] = "https://i.imgur.com/6nrYJCw.png";
filenames[4] = "https://i.imgur.com/XmPcBDa.png";
filenames[5] = "https://i.imgur.com/3OusOsv.png";
for (var i = 0; i < filenames.length; i++) {
imgArray[i] = loadImage(filenames[i]);
barnImg = loadImage("https://i.imgur.com/inS5Xdt.png");
cowImg = loadImage("https://i.imgur.com/8XjQyMt.png");
}
}
// methods
function stepChick() {
// update the chick image to animate
if(this.imgNum < chickArray.length - 2) {
// increment to next image
this.imgNum++;
} else {
// if at end of array reset to beginning
this.imgNum = 0;
}
}
function drawChick() {
// draw image
image(imgArray[this.imgNum], this.x, this.y, 50, 50);
}
function drawOneHill() {
// draw hill
fill(this.c);
stroke(0, 150, 0);
strokeWeight(1);
ellipse(this.x, this.y, this.w, this.hi);
this.x -= this.s; // decrement by speed
}
function drawTree() {
// draw trunk
stroke(77, 38, 0);
strokeWeight(3);
line(this.x, this.y, this.x, this.y + (this.h * .8));
line(this.x, this.y + this.h * .5, this.x + this.w * .2,
this.y + this.h * .2);
line(this.x, this.y + this.h * .7, this.x - this.w * .1,
this.y + this.h * .1);
// draw leaves
fill(this.c);
stroke(0, 100, 0);
strokeWeight(1);
ellipse(this.x, this.y, this.w, this.h);
this.x -= this.speed; // decrement by speed
}
// object constructor functions
function newChick(cx, cy) {
// constructor to make a chick
var c = {x: cx, y: cy,
imgNum: 0,
stepFunction: stepChick,
drawFunction: drawChick
}
return c;
}
function newHill(hx, hy, hw, hhi, hc, hs) {
// create new hill at x, y with diameter d
var h = {x: hx, y: hy, w: hw, hi: hhi,
c: hc, s: hs,
drawFunction: drawOneHill
};
return h;
}
function newTree(tx, ty, tw, th, tc, ts) {
// create new tree at x, y of height th, color tc
// tree width = tw, tree speed = ts
var t = {x: tx, y: ty, w: tw, h: th, c: tc,
speed: ts,
drawFunction: drawTree
};
return t;
}
function newFarm(fx, fy, fi, fw, fh, fb) {
// create new farm img at x, y
// use farm image fi
var f = {x: fx, y: fy, img: fi,
w: fw, h: fh,
speed: scrollSpeed,
barn: fb
};
return f;
}
function newPlane(px, py, pdx, pdy) {
// create plane object
var p = {x: px, y: py, dx: pdx, dy: pdy};
return p;
}
function setup() {
createCanvas(480, 480);
frameRate(10);
imageMode(CENTER);
// loop to create chick images
for(var i = 0; i < imgArray.length; i++) {
chickArray[i] = newChick(width/2, height * .7);
}
var onCanvas = true;
// generate initial hills
var numHills = floor(random(15, 20));
// onCanvas = true for first set of hills to draw on canvas
generateHills(onCanvas, numHills);
// create a farm
generateFarm();
// generate initial trees
var numTrees = floor(random(1, 10));
// onCanvas = true trees drawn on canvas
generateTrees(onCanvas, numTrees, 1);
generateTrees(onCanvas, numTrees, 2);
generateTrees(onCanvas, numTrees, 3);
}
function draw() {
// call all the parts of the scrolling background
background(153, 179, 255);
drawSun();
// draw hills
drawHills();
removeHills();
createNewHills();
foreground();
// draw farm elements, barns and cows
drawFarm();
removeFarm();
createNewFarm();
// draw trees
drawTrees();
removeTrees();
createNewTrees(1);
createNewTrees(2);
createNewTrees(3);
// animate the little chick
drawLittleChick();
// draw plane
createPlane();
drawPlane();
}
function drawSun() {
// draw stationary sun
fill(255, 255, 77, 200);
stroke(255, 255, 26);
strokeWeight(1);
ellipse(width * .85, height * .1, 50, 50);
}
function foreground(){
// draw grass
fill(0, 153, 51);
noStroke();
rect(0, height/3, width, height);
// draw path
stroke(153, 102, 51);
strokeWeight(20);
line(0, height * .75, width, height * .75);
// draw pebbles
// generate differnt shades of tan
stroke(random(210, 250), random(125, 220), random(85, 220));
strokeWeight(3);
var y = floor(random(height * .75 - 10, height * .75 + 10));
var x = floor(random(0, width));
point(x, y);
}
function drawLittleChick() {
// loop through chick array call step and draw methods
for(var i = 0; i < chickArray.length; i++) {
var currentChick = chickArray[i];
currentChick.stepFunction();
currentChick.drawFunction();
}
}
function createPlane() {
// probability of a plane
var newPlaneLikely = .0008;
if(random(0, 1) < newPlaneLikely & !flyingPlane) {
var y = floor(random(40, 100));
var x = 0;
var dx = random(2, 5);
var dy = random(.1, .8);
planeObj = newPlane(x, y, dx, dy);
flyingPlane = true;
}
}
function drawPlane() {
if(flyingPlane) {
stroke(230, 255, 255);
strokeWeight(3);
line(planeObj.x, planeObj.y, planeObj.x + 30, planeObj.y - 2);
// draw wings
strokeWeight(1);
line(planeObj.x + 18, planeObj.y - 2, planeObj.x + 3,
planeObj.y + 5);
line(planeObj.x + 18, planeObj.y - 1, planeObj.x + 20,
planeObj.y - 10);
// draw tail
line(planeObj.x, planeObj.y, planeObj.x - 3, planeObj.y -8);
planeObj.x += planeObj.dx;
planeObj.y -= planeObj.dy;
if(planeObj.x > width || planeObj.y < 0) {
flyingPlane = false;
}
}
}
function createNewHills() {
// probability of a hill
var newHillLikely = .07;
if(random(0, 1) < newHillLikely) {
var numHills = floor(random(5, 12));
var onCanvas = false;
generateHills(onCanvas, numHills);
}
}
function removeHills() {
// if array has more items and hills have scrolled off screen
var keep = [];
if(hills.length >= 0) {
for(var i = 0; i < hills.length; i++) {
if(hills[i].x + hills[i].w/2 > 0) {
keep.push(hills[i]);
}
}
hills = keep;
}
}
function drawHills() {
// draw hills on canvas
for(var i = 0; i < hills.length; i++) {
var h = hills[i];
h.drawFunction();
}
}
function generateHills(onCanvas, num) {
// if onCanvas = true then generate first set of hills
// on canvas, otherwise generate off canvas
// generate num number of new hills
for(var i = 0; i < num; i++) {
// generate hill color
var g = floor(random(50, 230));
var c = color(80, g, 0);
// generate x, y, width, and height of hill
var y = random(height/2.6, height/2);
var w = random(100, width);
var h = random(150, 250);
if(onCanvas) {
// generate hills on canvas
var x = random(-w, width + w * 3);
var w = random(width/2, width);
} else {
// generate hills off canvas
var x = random(width + (w * 1.5), width * 3);
}
var hill = newHill(x, y, w, h, c, 5);
hills.push(hill);
}
}
function createNewFarm(){
// probability of a farm
var newFarmLikely = .01;
if(random(0, 1) < newFarmLikely) {
generateFarm();
}
}
function removeFarm() {
// if array has more items and farms have scrolled off screen
var keep = [];
if(farm.length >= 0) {
for(var i = 0; i < farm.length; i++) {
if(farm[i].x + farm[i].w > 0) {
keep.push(farm[i]);
}
}
farm = keep;
}
}
function generateFarm() {
// create cows on farm
var isBarn = false
var numCows = floor(random(10, 30));
for(var i = 0; i < numCows; i++) {
// create a cow object and add it to the farm
// array for each cow
var x = random(width, width * 4);
var y = random(height/2.2, height/3.5);
if(y < height/2.7) {
// make cows smaaller, they are further away
var w = random(10, 15);
var h = random(10, 15);
} else {
// make cows bigger, they are closer
var w = random(25, 30);
var h = random(25, 30);
}
var c = newFarm(x, y, cowImg, w, h, isBarn);
farm.push(c);
}
// randomly generate barn variables
var x = random(width + w, width * 2);
var y = random(height/2.6, height/3.7);
// if barn is further away, draw it smaller
if(y < height/3.2) {
var w = random(20, 40);
var h = random(20, 40);
} else {
// close and bigger
var w = random(60, 90);
var h = random(50, 70);
}
isBarn = true;
var f = newFarm(x, y, barnImg, w, h, isBarn);
farm.push(f);
}
function drawFarm() {
// draw farm on canvas
var barnArray = [];
if(farm.length > 0) {
for(var i = 0; i < farm.length; i++) {
var f = farm[i];
if(f.barn) {
barnArray.push(f);
} else {
// draw cows behind barns
image(f.img, f.x, f.y,
f.w, f.h);
f.x -= f.speed;
}
}
// draw barns in their own layer on top of cows
for(var i = 0; i < barnArray.length; i++) {
var b = barnArray[i];
image(b.img, b.x, b.y, b.w, b.h);
b.x -= b.speed;
}
barnArray = [];
}
}
function createNewTrees(layer) {
var newTreeLikely = .012;
var numTrees = floor(random(2, 4));
// send false to generate off canvas
var onCanvas = false;
if(random(0, 1) < newTreeLikely) {
generateTrees(onCanvas, numTrees, layer);
}
}
function removeTrees() {
// if array has more items and trees have scrolled off screen
var keep = [];
if(trees.length >= 0) {
for(var i = 0; i < trees.length; i++) {
if(trees[i].x + trees[i].w > 0) {
keep.push(trees[i]);
}
}
trees = keep;
}
}
function drawTrees() {
// draw trees on canvas
if(trees.length >= 0) {
for(var i = 0; i < trees.length; i++) {
var t = trees[i];
t.drawFunction();
}
}
}
function generateTrees(start, num, layer) {
// if start = true then generate first set of trees
// on canvas, otherwise generate off canvas
// generate num number of new trees
for(var i = 0; i < num; i++) {
// generate tree color
var r = floor(random(70, 100));
var g = floor(random(80, 255));
var b = floor(random(80, 120));
if(layer == 1) {
var c = color(r, g, b, 190);
// create big trees in background
bigTrees(start, c);
} else if(layer == 2) {
r = floor(random(0, 150));
g = floor(random(50, 150));
b = floor(random(250, 255));
var c = color(r, g, b, 190);
// create little trees in midground
littleTrees(start, c);
} else {
r = floor(random(250, 255));
g = floor(random(30, 150));
b = floor(random(80, 255));
var c = color(r, g, b, 200);
// create shrubs in foreground
shrubs(start, c);
}
}
}
function bigTrees(start, c) {
// generate x, y, width, and height of trees
var w = random(50, 70);
var h = random(40, 70);
var y = random(height/2.6, height/2.8);
if(start) {
// generate trees on canvas
var x = random(5, width);
} else {
// generate trees off canvas
var x = random(width + w/2, width * 3);
}
// create tree and add to array
var tree = newTree(x, y, w, h, c, 5);
trees.push(tree);
}
function littleTrees(start, c) {
// generate x, y, width, and height of trees
var w = random(30, 40);
var h = random(15, 40);
var y = random(height/1.7, height/2);
if(start) {
// generate trees on canvas
var x = random(5, width);
} else {
// generate trees off canvas
var x = random(width + w/2, width * 2);
}
// create tree and add to array
var tree = newTree(x, y, w, h, c, 5);
trees.push(tree);
}
function shrubs(start, c) {
// generate x, y, width, and height of trees
var w = random(20, 40);
var h = random(15, 20);
var y = random(height/1.1, height/1.3);
if(start) {
// generate trees on canvas
var x = random(5, width);
} else {
// generate trees off canvas
var x = random(width + w/2, width * 3);
}
// create tree and add to array
var tree = newTree(x, y, w, h, c, 5);
trees.push(tree);
}
//PLANET VARIABLES:
var numPlanets = 4;
var planet = {x: [], y: [], s: [], r: [], g: [], b: [], dx: []};
var d = [];
//STAR VARIABLES:
var numStars = 100;
var star = {x: [], y: [], s: [], dx: []};
//IMG VARIABLES:
var porthole;
var astroLinks = ["https://i.imgur.com/FrLKzou.png",
"https://i.imgur.com/vdhX4kE.png",
"https://i.imgur.com/01Kk3J7.png"];
var astroPics = [];
var astro = {x: [], y: [], s: [], dx: [], e: []};
function preload(){
for(k = 0; k < 3; k++){
astroPics[k] = loadImage(astroLinks[k]);
}
porthole = loadImage("https://i.imgur.com/YSSOdgW.png") //made this porthole graphic myself
}
function setup() {
createCanvas(480, 480);
background(0);
planetInitialize();
starInitialize();
astroInitialize();
}
function draw() {
background(0);
starUpdate();
planetUpdate();
astroUpdate();
image(porthole, 0, 0, width, height);
}
function drawPlanetA(x, y, s, i){ //option one for planet type (moon-y)
strokeWeight(0);
fill(planet.r[i], planet.g[i], planet.b[i]); //randomized color
ellipse(x, y, s, s);
fill(planet.r[i] + 20, planet.g[i] + 20, planet.b[i] + 20); //randomized color, but a little bit lighter
ellipse(x - s/10, y + s/3, s/4);
ellipse(x + s/5, y - s/10, s/3);
ellipse(x - s/4, y - s/5, s/7);
}
function drawPlanetB(x, y, s, i){ //option two for planet type (saturn-y)
fill(planet.r[i], planet.g[i], planet.b[i]);
ellipse(x, y, s, s);
strokeWeight(3);
stroke(255-planet.r[i], 255-planet.g[i], 255-planet.b[i]);
line(x - s*(2/3), y, x + s*(2/3), y);
strokeWeight(0);
}
function starUpdate(){
for(var j = 0; j < numStars; j++){
strokeWeight(0)
fill(250, 248, 235); //creamy white
ellipse(star.x[j], star.y[j], star.s[j], star.s[j]);
if(star.x[j] >= width + star.s[j]){ //if star has fully moved off screen, I reset the values
star.s[j] = random(1, 10);
star.x[j] = random(-20, 0-star.s[j]); //HOWEVER, I reset the values with the X position offscreen, so there appears to be a continuous scroll
star.y[j] = random(0, height);
star.dx[j] = star.s[j] / 200;
}else{
star.x[j] += star.dx[j]; //if star is not offscreen, it moves to the right
}
}
}
function planetUpdate(){
for(var i = 0; i < numPlanets; i++){
if(d[i] <= 1){ //selects planet type: if d is less than/equal to one, planet A is drawn, if d is greater than one, planet B is drawn
drawPlanetA(planet.x[i], planet.y[i], planet.s[i], i);
}else if(d[i] > 1){
drawPlanetB(planet.x[i], planet.y[i], planet.s[i], i);
}
if(planet.x[i] >= width + planet.s[i] + (planet.s[i] * (2/3))){ //if planet has fully moved off screen, I reset the values
planet.s[i] = random(10, 150);
planet.x[i] = random(-200, 0-planet.s[i]); //HOWEVER, I reset the values with the X position offscreen, so there appears to be a continuous scroll
planet.y[i] = random(0, height);
planet.r[i] = random(20, 235);
planet.g[i] = random(20, 235);
planet.b[i] = random(20, 235);
planet.dx[i] = planet.s[i] / 200;
}else{
planet.x[i] += planet.dx[i]; //if planet is not offscreen, it moves to the right
}
}
}
function astroUpdate(){
for(var k = 0; k < 3; k++){
image(astroPics[k], astro.x[k], astro.y[k], astro.s[k], astro.s[k]);
if(astro.x[k] >= astro.e[k]){
astro.x[k] = random(-2000, -150);
astro.y[k] = random(0, height);
astro.s[k] = random(30, 400);
astro.dx[k] = astro.s[k] / 200;
astro.e[k] = random(height+150, 2000);
}else{
astro.x[k] += astro.dx[k];
}
}
}
function planetInitialize(){
for(var i = 0; i < numPlanets; i++){
planet.x[i] = random(0, width); //x position
planet.y[i] = random(0, height); //y position
planet.s[i] = random(10, 150); //size
planet.r[i] = random(20, 235); //r, g, and b are randomized. I seperated these instead of creating a color variable so I could use R, G, and B to edit the details
planet.g[i] = random(20, 235);
planet.b[i] = random(20, 235);
planet.dx[i] = planet.s[i] / 200; //dx is related to the size of the planet, if it's bigger it will appear to move quicker
d[i] = (random(0, 2)); //variable d selects whether or not planet type A or B is selected
}
}
function starInitialize(){
for(var j = 0; j < numStars; j++){
star.x[j] = random(0, width);
star.y[j] = random(0, height);
star.s[j] = random(1, 10);
star.dx[j] = star.s[j] / 200; //dx is related to the size of the star, if it's bigger it will appear to move quicker
}
}
function astroInitialize(){
for(var k = 0; k < 3; k++){
astro.x[k] = random(-2000, width)
astro.y[k] = random(0, height);
astro.s[k] = random(30, 150);
astro.dx[k] = astro.s[k] / 200;
astro.e[k] = random(height+150, 2000); //astro end: beginning/end determines where image starts/ends it's journey before reset. I made the value larger so there would be greater diversity in when astronaunts appeared
}
}