p5.js之动态魔幻画板

基于p5.js的魔幻画板

一.起因

本学期的互动媒体技术大作业要求每个人做一个“绘画系统”,提供一系列绘画材料(例如画笔/颜料/滤镜)给用户操作,以创作出动态/交互的绘画作品。这个绘画系统是对“绘画”的概念的扩展,但仍然体现出与传统绘画系统的相似性。

二.扩展绘画和常规绘画的区别

概念解释

按照文章《什么是绘画?——以抽象思维理解绘画》对于“绘画”的界定,绘画可以看作四个要素的构成:
材料:颜料,画布,画笔等物质要素;
作画者:创作的思想/技法有关的内容;
交互方式:作画者如何操作材料;
作品:即呈现效果。通常的绘画作品;

补充说明:
材料并不直接决定它如何与人交互,实际上可以有不同的交互方式。例如,画笔的交互方式通常是将其直接接触到画布,但波洛克那样的泼洒画法,却采取了不接触画布的交互方式。

通常的画图工具比如电脑自带的“画图”软件,提供多种调色版以及画笔,以及丰富的简单几何图形供用户选择。但在这样的绘画系统中所做的绘画都是静态的,如何让所画的图形具有动态感和新特色,成为我选题的难点。p5.js之动态魔幻画板_第1张图片
这里博主想要创作的扩展绘画是对传统绘画的视觉效果进行扩展,让作品呈现出动态和交互性。例如,作品呈现为一系列不同位置形态大小的几何形,玩家不仅是“看见”,还可以去“拖拽”,甚至点击图形产生音乐。
博主的编码水平有限,参考了网上的很多资料,但思维的局限性决定了博主还是脱离不开传统的绘画交互方式,即使用画笔与画布直接接触。一开始是使用网上开源的p5.js的一个DrawingByCodingTutorialDemos-master文件夹加以改进,效果如下图:
p5.js之动态魔幻画板_第2张图片
这是博主绘画系统创作的雏形,此时已经能控制画笔和画布的颜色,简单的读取和保存图片,然后可以看到右上方还未完成的调色画板。我本来打算继续完成,但由于原文件过于复杂修改起来十分麻烦,我于是寻找其它可能性。

三.突破

在我为如何重新设计我的绘画系统为难的时候,另一位博主的这篇文章给了我启发。在这个绘画系统中,不仅设计出了动态的画笔种类,而且还能控制背景颜色,切换动态和静态模式,保存图片以及“加速”或者让“时间”停止。由于原博主已经附上代码所以这里就不再赘述了。这让我认识到使用p5.js居然能创造出如此好玩的画板,不过此时的画笔种类以及可选颜色还比较少,我决定在此基础上加以改进。

四.新的魔幻画板

p5.js之动态魔幻画板_第3张图片

可以看到初始界面我增加了画板的种类特别是我认为比较常用的黑白两色画板。画板的颜色可以用鼠标直接点击切换,也可以使用快捷键,按从左到右的’U’字顺序依次对应“A”到“Z”的26个英文字母。画布的颜色分为白天和黑夜两种模式,本来想换点其他颜色,但可能是自己审美的问题,选了好几种颜色都不太满意,并且白天和黑夜的logo我觉得也蛮好的所以最后就不换了。下面用一个简单的gift图展示一下魔幻画板的神奇之处吧。(这个水印有点大将就下看)
p5.js之动态魔幻画板_第4张图片

画笔的种类一共有7种,分别是基础的圆、三角形、直线和滑稽脸、雪花、五角星以及水滴。本来打算使用加载现有的图片完成更酷的动态效果,但由于p5.js加载图片一直显示loading,响应时间较长,最终自己编写代码实现绘图效果。

下面附上魔幻画板的代码:`

///
//===============================================//
//Floating Light v2.0 - By Li Zhiheng//
//===============================================//
///

/*
This work was originally inspired by Van Gogh's starry night and scraped painting.
I have seen the dynamic starry night made by openFramework, it's wonderful and amazing.
This is the reason why I decided to make a dynamic drawing tool.
You can control the flow of time and create dynamic particles, 
so it is easy to complete the amazing effect.

Shortcut key:
0-6:function buttons
A-Z:color buttons
L Shift: Hide the menu.
*/


//Global Variable

var objs = [];
var btns = [];
var FPS = 60;
var timepast = 0;
var R = 200;
var G = 150;
var B = 50;
var bR = 0;
var bG = 0;
var bB = 50;
var eraserRange = 20;
var timerRange = 50;
var brushType = "CIRCLE";
var pbrushType = "CIRCLE";
var isPlaying = true;
var isMenuHide = false;
//滑稽脸
function huaji(x,y,size,l){
  //stroke(252,186,12); 
  noStroke();
  fill(237,148,14);
  ellipse(x,y,1.06*size);
  fill(252,222,12);
  ellipse(x,y,size);//脸
  
  fill(173,91,10);
  arc(x, y, 0.8*size, 0.8*size, 0, PI, CHORD);
  fill(252,222,12);
  arc(x, y-0.01*size, 0.8*size, 0.7*size, 0, PI, CHORD);//笑
  
  fill(254,240,205);
  arc(x-0.25*size, y, 0.8*size, 0.6*size, 1.3*PI,1.7* PI, PIE);
  fill(252,222,12);
  arc(x-0.25*size, y, 0.8*size, 0.5*size, 1.3*PI,1.7* PI, PIE);
  
  
  fill(254,240,205);
  arc(x+0.25*size, y, 0.8*size, 0.6*size, 1.3*PI,1.7* PI, PIE);
  fill(252,222,12);
  arc(x+0.25*size, y, 0.8*size, 0.5*size, 1.3*PI,1.7* PI, PIE);//眼壳子
  if(l==-1){
  fill(173,91,10);
  ellipse(x-0.34*size,y-0.28*size,0.1*size);
  ellipse(x+0.16*size,y-0.28*size,0.1*size);//眼珠
  }
  if(l==1){
  fill(173,91,10);
  ellipse(x-0.1*size,y-0.28*size,0.1*size);
  ellipse(x+0.35*size,y-0.28*size,0.1*size);//眼珠
  
  
  }
  
  fill(58,43,1);
  arc(x-0.28*size, y-0.35*size,0.20*size, 0.20*size, 1.1*PI,2.1* PI, OPEN);
  fill(252,222,12);
  arc(x-0.28*size, y-0.35*size, 0.21*size, 0.16*size, 1*PI,2.2* PI, OPEN);
  
  fill(58,43,1);
  arc(x+0.28*size, y-0.35*size,0.20*size,0.20*size, 0.9*PI,1.9* PI, CHORD);
  fill(252,222,12);
  arc(x+0.28*size, y-0.35*size, 0.21*size, 0.15*size, 0.9*PI,1.9* PI, CHORD);//眉毛

  
  fill(241,74,56);
  ellipse(x-0.25*size,y-0.18*size,0.25*size,0.07*size);
  ellipse(x+0.25*size,y-0.18*size,0.25*size,0.07*size);
}



//FunctionButton

function FuncBtn(X, Y, W, H, CMD) {
  this.x = X;
  this.y = Y;
  this.w = W;
  this.h = H;
  this.cmd = CMD;
}
FuncBtn.prototype.isMouseInBtn = function() {
  if (mouseX >= this.x && mouseX <= this.x + this.w &&
    mouseY >= this.y && mouseY <= this.y + this.h) {
    return true;
  } else {
    return false;
  }
}
FuncBtn.prototype.clickBtn = function() {
  print("ClickBtn!");
  if (this.cmd == "sun") {
    bR = 200;
    bG = 255;
    bB = 255;
    this.cmd = "moon";

  } else if (this.cmd == "moon") {
    bR = 0;
    bG = 0;
    bB = 50;
    this.cmd = "sun";
  } else if (this.cmd == "pause") {
    isPlaying = false;
    for (var i = 0; i < objs.length; i++) {
      objs[i].isPlaying = false;
    }
    this.cmd = "play";

  } else if (this.cmd == "play") {
    isPlaying = true;
    for (var i = 0; i < objs.length; i++) {
      objs[i].isPlaying = true;
    }
    this.cmd = "pause";

  } else if (this.cmd == "timer") {
    brushType = "TIMER";

  } else if (this.cmd == "eraser") {
    brushType = "ERASER";
  } else if (this.cmd == "clear") {
    objs = [];
 } else if (this.cmd == "save") {
     saveCanvas("Painting", "jpg")
  } else if (this.cmd == "circle") {
    brushType = "TRIANGLE";
    pbrushType = "CIRCLE";
    this.cmd = "triangle";

  } else if (this.cmd == "triangle") {
    brushType = "LINES";
    pbrushType = "TRIANGLE";
    this.cmd = "lines";

  } else if (this.cmd == "lines") {
    brushType = "RECT";
    pbrushType = "LINES";
    this.cmd = "rect";
  }
  else if (this.cmd == "rect") {
    brushType = "RAINDROP";
    pbrushType = "RECT";
    this.cmd = "raindrop";
  }
	 else if (this.cmd == "raindrop") {
    brushType = "SNOWFLAKE";
    pbrushType = "RAINDROP";
    this.cmd = "snowflake";
  }
	else if (this.cmd == "snowflake") {
    brushType = "PENTAGRAM";
    pbrushType = "SNOWFLAKE";
    this.cmd = "pentagram";
  }
	else if (this.cmd == "pentagram") {
    brushType = "CIRCLE";
    pbrushType = "PENTAGRAM";
    this.cmd = "circle";
  }
}



FuncBtn.prototype.displayBtn = function() {
  stroke(0);
  strokeWeight(1);
  fill(255, 255, 255);
  rect(this.x, this.y, this.w, this.h, 5);


  if (this.cmd == "sun") {
    fill(255, 50, 50);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    for (var i = 0; i < 8; i++) {
      rotate(PI / 4.0);
      line(0, 0, 8, 8);
    }
    resetMatrix();
    ellipse(this.x + this.w / 2, this.y + this.h / 2, 15, 15);


  } else if (this.cmd == "moon") {
    fill(255, 255, 50);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    arc(-5, 0, 25, 25, PI + HALF_PI, HALF_PI, CHORD);
    resetMatrix();

  } else if (this.cmd == "pause") {
    fill(0);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    rectMode(CENTER);
    rect(-4, 0, 4, 15);
    rect(4, 0, 4, 15);
    rectMode(CORNER);
    resetMatrix();
  } else if (this.cmd == "play") {
    fill(0);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    triangle(-2, -8, -2, 8, 6, 0);
    resetMatrix();
  } else if (this.cmd == "timer") {

    translate(this.x + this.w / 2, this.y + this.h / 2);
    noFill();
    ellipse(0, 0, 22, 22);
    ellipse(0, 0, 25, 25);
    fill(0);
    ellipse(0, 0, 3, 3);
    strokeWeight(2);
    line(0, 0, 5, 0);
    line(0, 0, 0, -7);
    resetMatrix();
  } else if (this.cmd == "eraser") {
    fill(0);
    noStroke();
    translate(this.x + this.w / 2, this.y + this.h / 2);
    textSize(25);
    textAlign(CENTER);
    textStyle(BOLD);
    text("E", 0, 8);
    resetMatrix();
  } else if (this.cmd == "clear") {

    fill(0);
    noStroke();
    translate(this.x + this.w / 2, this.y + this.h / 2);
    textSize(25);
    textAlign(CENTER);
    textStyle(BOLD);
    text("C", 0, 8);
    resetMatrix();
} else if (this.cmd == "save") {

    fill(0);
    noStroke();
    translate(this.x + this.w / 2, this.y + this.h / 2);
    textSize(25);
    textAlign(CENTER);
    textStyle(BOLD);
    text("S", 0, 8);
    resetMatrix();
  } else if (this.cmd == "circle") {

    fill(0);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    ellipse(6, -2, 10, 10);
    ellipse(-5, -5, 5, 5);
    ellipse(3, 8, 4, 4);
    resetMatrix();

  } else if (this.cmd == "triangle") {

    fill(0);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    triangle(0, 0, 10, 0, 5, -8);
    triangle(-5, 8, 5, 8, 0, 0);
    triangle(-8, -5, -3, -5, -5.5, -9);
    resetMatrix();

  } else if (this.cmd == "lines") {

    fill(0);
    strokeWeight(2);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    line(-5, -10, 5, 0);
    line(-10, -10, 10, 10);
    line(-5, 0, 5, 10);
    resetMatrix();

  }
  else if (this.cmd == "rect") {

   
    translate(this.x + this.w / 2, this.y + this.h / 2);
    huaji(0,0,30,1);
    resetMatrix();

  }
	else if (this.cmd == "raindrop") {

    fill(50,150,200);
    strokeWeight(0);
    translate(this.x + this.w / 2, this.y + this.h / 2);
		triangle(0,-10,2.5*PI,2.5*PI,-2.5*PI,2.5*PI);
    arc(0,2,20,20,0.5*HALF_PI,1.5*HALF_PI);
    resetMatrix();

  }
	else if (this.cmd == "snowflake") {

    fill(50,150,200);
    strokeWeight(1.5);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    line(-10, 0, 10, 0);
    line(0, 10, 0, -10);
    line(-7, -7, 7, 7);
		line(-7, 7, 7, -7);
    resetMatrix();

  }
	else if (this.cmd == "pentagram") {

    fill(0);
    strokeWeight(2);
    translate(this.x + this.w / 2, this.y + this.h / 2);
    line(-10, -7, 10, -7);
    line(10, -7, -7, 7);
    line(-7, 7, 0, -15);
		line(0, -15, 7, 7);
		line(7,7,-10,-7);
    resetMatrix();

  }
}



//ColorButton

function ColorBtn(X, Y, W, H, givenR, givenG, givenB) {
  this.x = X;
  this.y = Y;
  this.w = W;
  this.h = H;
  this.r = givenR;
  this.g = givenG;
  this.b = givenB;
}
ColorBtn.prototype.isMouseInBtn = function() {
  if (mouseX >= this.x && mouseX <= this.x + this.w &&
    mouseY >= this.y && mouseY <= this.y + this.h) {
    return true;
  } else {
    return false;
  }
}
ColorBtn.prototype.clickBtn = function() {
  R = this.r;
  G = this.g;
  B = this.b;
  if (brushType == "ERASER" || brushType == "TIMER") {
    brushType = pbrushType;
  }
}
ColorBtn.prototype.displayBtn = function() {
  stroke(0);
  strokeWeight(1);
  fill(this.r * 1.5, this.g * 1.5, this.b * 1.5);
  rect(this.x, this.y, this.w, this.h, 5);
}


//Node

function Node(position, givenSize, givenR, givenG, givenB) {
  this.R = givenR;
  this.G = givenG;
  this.B = givenB;
  this.position = createVector(position.x, position.y);
  this.position.x += (random(20) - 10);
  this.position.y += (random(20) - 10);
  this.size = createVector(0, 0);
  this.sizeScale = 0.5;
  var randomSize = givenSize / 2 + random(10);
  this.baseSize = createVector(randomSize, randomSize);
  this.timepast = 0;
  this.isPlaying = isPlaying;
  this.rotateAngle = random(2 * PI);
  this.shapeType = brushType;
  this.pmouseX = pmouseX;
  this.pmouseY = pmouseY;
  this.mouseX = mouseX;
  this.mouseY = mouseY;
}
Node.prototype.drawing = function() {
  noStroke();
  if (this.shapeType == "CIRCLE") {
    translate(this.position.x, this.position.y);
    fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, round(sin(this.timepast) * 128));
    ellipse(sin(this.timepast) * this.baseSize.x, cos(this.timepast) * this.baseSize.y, this.size.x * 1.25, this.size.y * 1.25);
    fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, 255);
    ellipse(sin(this.timepast) * this.baseSize.x, cos(this.timepast) * this.baseSize.y, this.size.x, this.size.y);
    resetMatrix();

  } else if (this.shapeType == "TRIANGLE") {
    translate(this.position.x, this.position.y);
    rotate(this.rotateAngle);
    fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, round(sin(this.timepast) * 128));
    triangle(sin(this.timepast) * this.baseSize.x - this.size.x * 1.5 * 0.5,
      cos(this.timepast) * this.baseSize.y - this.size.y * 1.5 * 0.5,

      sin(this.timepast) * this.baseSize.x + this.size.x * 1.5 * 0.5,
      cos(this.timepast) * this.baseSize.y - this.size.y * 1.5 * 0.5,

      sin(this.timepast) * this.baseSize.x * 0.5,
      cos(this.timepast) * this.baseSize.y + this.size.y * 1.5 * 0.9 * 0.5);

    fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, 255);
    triangle(sin(this.timepast) * this.baseSize.x - this.size.x * 0.5,
      cos(this.timepast) * this.baseSize.y - this.size.y * 0.5,

      sin(this.timepast) * this.baseSize.x + this.size.x * 0.5,
      cos(this.timepast) * this.baseSize.y - this.size.y * 0.5,

      sin(this.timepast) * this.baseSize.x * 0.5,
      cos(this.timepast) * this.baseSize.y + this.size.y * 0.9 * 0.5);
    resetMatrix();


  } else if (this.shapeType == "LINES") {
    //translate(this.position.x,this.position.y);
    // rotate(this.rotateAngle);

    strokeWeight(2 + this.size.x / 1.5 * 0.75);
    stroke(this.size.x * this.R / 8, this.size.x * this.G / 8, this.size.x * this.B / 8, round(sin(this.timepast) * 128));
    line(this.pmouseX, this.pmouseY, this.mouseX, this.mouseY);
    strokeWeight(1.5 + this.size.x / 1.5 * 0.5);
    stroke(this.size.x * this.R / 8, this.size.x * this.G / 8, this.size.x * this.B / 8, 255);
    line(this.pmouseX, this.pmouseY, this.mouseX, this.mouseY);
    //resetMatrix();
  }
  else if (this.shapeType == "RECT") {
    //translate(this.position.x,this.position.y);
    // rotate(this.rotateAngle);

    //translate(this.position.x, this.position.y);
    huaji(this.position.x,this.position.y,50,1);
   // resetMatrix();
  }
	else if (this.shapeType == "RAINDROP") {
    //translate(this.position.x,this.position.y);
    // rotate(this.rotateAngle);

   // translate(this.position.x, this.position.y);
		fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, 255);
    strokeWeight(2 + this.size.x / 1.5 * 0.75);
    stroke(this.size.x * this.R / 8, this.size.x * this.G / 8, this.size.x * this.B / 8, round(sin(this.timepast) * 128));
    strokeWeight(2);
   
		triangle(this.position.x,this.position.y-10,this.position.x+2.5*PI,this.position.y+2.5*PI,this.position.x-2.5*PI,this.position.y+2.5*PI);
    arc(this.position.x,this.position.y+2,20,20,0.5*HALF_PI,1.5*HALF_PI);
    resetMatrix();
  }
	else if (this.shapeType == "SNOWFLAKE") {
    //translate(this.position.x,this.position.y);
    // rotate(this.rotateAngle);
    fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10);
    strokeWeight(this.size.x / 1.5 * 0.75);
    stroke(this.size.x * this.R / 8, this.size.x * this.G / 8, this.size.x * this.B / 8);
  
		line(this.position.x-10, this.position.y, this.position.x+10, this.position.y);
    line(this.position.x, this.position.y+10, this.position.x,this.position.y-10);
    line(this.position.x-7, this.position.y-7, this.position.x+7,this.position.y+7);
		line(this.position.x-7, this.position.y+7, this.position.x+7, this.position.y-7)
		
		fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, 255);
    strokeWeight(this.size.x / 1.5 * 0.75);
    stroke(this.size.x * this.R / 8, this.size.x * this.G / 8, this.size.x * this.B / 8, round(sin(this.timepast) * 128));
    line(this.position.x-5, this.position.y, this.position.x+5, this.position.y);
    line(this.position.x, this.position.y+5, this.position.x,this.position.y-5);
    line(this.position.x-3, this.position.y-3, this.position.x+3,this.position.y+3);
		line(this.position.x-3, this.position.y+3, this.position.x+3, this.position.y-3);
	
    //resetMatrix();+
}
	else if (this.shapeType == "PENTAGRAM") {
    //translate(this.position.x,this.position.y);
    // rotate(this.rotateAngle);

   // translate(this.position.x, this.position.y);
		fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, 255);
    strokeWeight(2 + this.size.x / 1.5 * 0.75);
    stroke(this.size.x * this.R / 8, this.size.x * this.G / 8, this.size.x * this.B / 8);
    strokeWeight(2);
   
	  line(this.pmouseX-10, this.pmouseY-7, this.pmouseX+10, this.pmouseY-7);
    line(this.pmouseX+10, this.pmouseY-7, this.pmouseX-7,this.pmouseY+ 7);
    line(this.pmouseX-7,this.pmouseY+7, this.pmouseX, this.pmouseY-15);
		line(this.pmouseX, this.pmouseY-15, this.pmouseX+7, this.pmouseY+7);
		line(this.pmouseX+7,this.pmouseY+7,this.pmouseX-10,this.pmouseY-7);
   
    resetMatrix();
  }
}
Node.prototype.update = function() {
  this.size = createVector(this.baseSize.x + sin(this.timepast) * this.baseSize.x * this.sizeScale,
    this.baseSize.y + sin(this.timepast) * this.baseSize.y * this.sizeScale);
  if (this.isPlaying) {
    this.timepast += 1 / FPS;
  }
}


//Setup


function setup() {
  frameRate(FPS);//?
  createCanvas(800, 800);
  noCursor();//?
  strokeCap(PROJECT);//?
  //======================
  //ButtonList
  //======================
  //Color Buttons
  btns.push(new ColorBtn(5, 5 + 40 * 0, 40, 40, 200, 50, 50));//?
  btns.push(new ColorBtn(5, 5 + 40 * 1, 40, 40, 200, 100, 50));
  btns.push(new ColorBtn(5, 5 + 40 * 2, 40, 40, 200, 150, 50));

  btns.push(new ColorBtn(5, 5 + 40 * 3, 40, 40, 150, 200, 50));
  btns.push(new ColorBtn(5, 5 + 40 * 4, 40, 40, 100, 200, 50));
  btns.push(new ColorBtn(5, 5 + 40 * 5, 40, 40, 50, 200, 50));

  btns.push(new ColorBtn(5, 5 + 40 * 6, 40, 40, 50, 150, 200));
  btns.push(new ColorBtn(5, 5 + 40 * 7, 40, 40, 50, 100, 200));
  btns.push(new ColorBtn(5, 5 + 40 * 8, 40, 40, 50, 50, 200));

  btns.push(new ColorBtn(5, 5 + 40 * 9, 40, 40, 100, 50, 200));
  btns.push(new ColorBtn(5, 5 + 40 * 10, 40, 40, 150, 50, 200));
  btns.push(new ColorBtn(5, 5 + 40 * 11, 40, 40, 200, 50, 200));
  btns.push(new ColorBtn(5, 5 + 40 * 12, 40, 40, 255, 255, 255));
	
	btns.push(new ColorBtn(45, 5 + 40 * 0, 40, 40, 160, 40, 40));//?
  btns.push(new ColorBtn(45, 5 + 40 * 1, 40, 40, 160, 90, 40));
  btns.push(new ColorBtn(45, 5 + 40 * 2, 40, 40, 160, 140, 40));

  btns.push(new ColorBtn(45, 5 + 40 * 3, 40, 40, 120, 190, 40));
  btns.push(new ColorBtn(45, 5 + 40 * 4, 40, 40, 80, 190, 40));
  btns.push(new ColorBtn(45, 5 + 40 * 5, 40, 40, 30, 190, 40));

  btns.push(new ColorBtn(45, 5 + 40 * 6, 40, 40, 30, 140, 190));
  btns.push(new ColorBtn(45, 5 + 40 * 7, 40, 40, 30, 80, 180));
  btns.push(new ColorBtn(45, 5 + 40 * 8, 40, 40, 30, 40, 180));

  btns.push(new ColorBtn(45, 5 + 40 * 9, 40, 40, 80, 40, 180));
  btns.push(new ColorBtn(45, 5 + 40 * 10, 40, 40, 130, 40, 180));
  btns.push(new ColorBtn(45, 5 + 40 * 11, 40, 40, 180, 40, 180));
  btns.push(new ColorBtn(45, 5 + 40 * 12, 40, 40, 0, 0, 0));
  //Function Buttons
  btns.push(new FuncBtn(5, 5 + 40 * 13, 40, 40, "sun"));
  btns.push(new FuncBtn(5, 5 + 40 * 14, 40, 40, "circle"));
  if(isPlaying){
    btns.push(new FuncBtn(5, 5 + 40 * 15, 40, 40, "pause"));
  }else{
    btns.push(new FuncBtn(5, 5 + 40 * 15, 40, 40, "play"));
  }
  btns.push(new FuncBtn(5, 5 + 40 * 16, 40, 40, "timer"));
  btns.push(new FuncBtn(45, 5 + 40 * 13, 40, 40, "eraser"));
  btns.push(new FuncBtn(45, 5 + 40 * 14, 40, 40, "clear"));
  btns.push(new FuncBtn(45, 5 + 40 * 15, 40, 40, "save"));
  
}



//Draw

function draw() {
  background(bR, bG, bB);
  timepast += 1 / FPS;
  if (!isMenuHide) {
    if (timepast < 5) {
      noStroke();
      textAlign(LEFT);
      textSize(15);
      fill(255 - bR);
      text("Floating Light v2.0 - Made By Li Zhiheng", 5, height - 10);
    } else if (timepast < 10) {
      noStroke();
      textAlign(LEFT);
      textSize(15);
      fill(255 - bR);
      text("Press Left Shift to hide Menu, Press S to save canvas to JPG.", 5, height - 10);
    }
  }
  //===================
  //Drawing Something
  //===================
  if (mouseIsPressed && (mouseX > 40 || isMenuHide)) {
    if (brushType == "CIRCLE" || brushType == "LINES" || brushType == "TRIANGLE"||brushType == "RECT"||brushType == "RAINDROP"||brushType == "SNOWFLAKE"||brushType == "PENTAGRAM") 
		{
      var position = createVector(mouseX, mouseY);
      objs.push(new Node(position, sqrt(sq(mouseX - pmouseX) + sq(mouseY - pmouseY)), R, G, B));
    }
    //Eraser
    else if (brushType == "ERASER" && objs.length > 0) {
      for (var i = 0; i < objs.length; i++) {
        if (sqrt(sq(objs[i].position.x - mouseX) + sq(objs[i].position.y - mouseY)) <= eraserRange) {
          objs.splice(i, 1);
          break;

        }
      }
    } else if (brushType == "TIMER" && objs.length > 0) {
      for (var i = 0; i < objs.length; i++) {
        if (sqrt(sq(objs[i].position.x - mouseX) + sq(objs[i].position.y - mouseY)) <= timerRange) {
          objs[i].timepast += 2 / FPS;
          objs[i].isPlaying = false;
        }
      }


    }
  }
  for (var i = 0; i < objs.length; i++) {
    objs[i].drawing();
    objs[i].update();
  }
  
  
  //=======================
  //Cursor Icon
  //=======================
  //Menu
  stroke(0);
  strokeWeight(2);
  if (!isMenuHide) {
    for (var i = 0; i < btns.length; i++) {
      btns[i].displayBtn();
      if (btns[i].isMouseInBtn()) {
        cursor(HAND);//?
      }
    }
  }

  //Canvas
  if (mouseX > 80 || isMenuHide) {
    noCursor();
    fill(R * 1.5, G * 1.5, B * 1.5);
    stroke(R * 1.5, G * 1.5, B * 1.5);
    if (brushType == "CIRCLE") {
      ellipse(mouseX, mouseY, 10, 10);
    } else if (brushType == "TRIANGLE") {
      triangle(mouseX - 5, mouseY + 3, mouseX + 5, mouseY + 3, mouseX, mouseY - 5);
    } else if (brushType == "LINES") {
      translate(mouseX, mouseY);
      noFill();
      stroke(255 - bR);
      ellipse(0, 0, 20, 20);
      fill(R * 1.5, G * 1.5, B * 1.5);
      noStroke();
      ellipse(0, 0, 6, 6);
      resetMatrix();
    } 
    else if (brushType == "RECT") {
      huaji(mouseX,mouseY,20,1);
    }
		else if (brushType == "RAINDROP") {
     triangle(mouseX,mouseY-10,mouseX+2.5*PI,mouseY+2.5*PI,mouseX-2.5*PI,mouseY+2.5*PI);
    arc(mouseX,mouseY+2,20,20,0.5*HALF_PI,1.5*HALF_PI);
    }
		else if (brushType == "SNOWFLAKE") {
    line(mouseX-10, mouseY, mouseX+10,mouseY);
    line(mouseX, mouseY+10, mouseX, mouseY-10);
    line(mouseX-7, mouseY-7, mouseX+7,mouseY+7);
	line(mouseX-7, mouseY+7, mouseX+7, mouseY-7);
    }
		else if (brushType == "PENTAGRAM") {
    line(mouseX-10, mouseY-7, mouseX+10, mouseY-7);
    line(mouseX+10, mouseY-7, mouseX-7,mouseY+ 7);
    line(mouseX-7,mouseY+7, mouseX, mouseY-15);
		line(mouseX, mouseY-15, mouseX+7, mouseY+7);
		line(mouseX+7,mouseY+7,mouseX-10,mouseY-7);
   
    }
    else if (brushType == "ERASER") {
      translate(mouseX, mouseY);
      noFill();
      stroke(255 - bR);
      ellipse(0, 0, eraserRange, eraserRange);
      resetMatrix();

    } else if (brushType == "TIMER") {
      translate(mouseX, mouseY);
      stroke(255 - bR);
      noFill();
      ellipse(0, 0, timerRange, timerRange);
      ellipse(0, 0, 22, 22);
      ellipse(0, 0, 25, 25);
      fill(255 - bR);
      ellipse(0, 0, 3, 3);
      strokeWeight(2);
      line(0, 0, 5, 0);
      line(0, 0, 0, -7);
      resetMatrix();
    }
  }
}

function mouseClicked() {
  if (!isMenuHide) {
    for (var i = 0; i < btns.length; i++) {
      if (btns[i].isMouseInBtn()) {
        btns[i].clickBtn();//键盘相应函数
      }
    }
  }
  return false;
}


//Shortcut Key


function keyPressed() {
  //print("keyCode is"+keyCode);
  if (keyCode >= 65 && keyCode <= 90) {
    btns[keyCode - 65].clickBtn();//颜色快捷键从左到右‘U’字顺序
  }
  if (keyCode == 48) { //0 功能快捷键从左到右‘U’字顺序
    btns[26].clickBtn();
  }
  if (keyCode == 49) {//1
    btns[27].clickBtn(); 
  }
  if (keyCode == 50) {//2
    btns[28].clickBtn();
  }
  if (keyCode == 51) { //3
    btns[29].clickBtn();
  }
  if (keyCode == 52) { //4
    btns[30].clickBtn();
  }
  if (keyCode == 53) { //5
    btns[31].clickBtn();
  }
  if (keyCode === 54) { //6
    btns[32].clickBtn();
  }

  if (keyCode == 16) { //Shift L
    isMenuHide = !isMenuHide;
  }

}


//To be continued...

总结

此次大作业还有很多局限之处,我本来想让雪花产生自转效果,水滴能自由落体但由于各种原因我未能实现;然后虽然给每个功能按钮以及画板按钮配置了快捷键,但感觉使用效率不如之前,比如CLEAR用’C’指代,现在用数字实现清除画布的功能就不是很方便记忆。此次大作业让我学会使用p5.js的基本图形来创作新的有趣图形,并使用填充和边框颜色的变化,产生运动效果,很好玩,希望日后能有机会把这个系统做的更加完善吧。

你可能感兴趣的:(新手教程,p5.js,魔幻画板)