Processing摸索前行(02)

69 篇文章 69 订阅
62 篇文章 28 订阅

一、对于完整模式setup和draw函数是必须的
经过第一次的摸索,已经基本掌握了他的大体框架,以及编写一个简单到极点的可以运行的程序。但是即使这么简单的程序,我在摸索的时候都遇到了一个问题。
这个问题是这样的,我们来看看代码:

void setup()
{
   size(400,300);
   background(255);
}

void keyPressed()
{
     println("hello this is key pressed!"); 
}

上述代码写好后,我并未感觉哪里有错,编译器也没有指出哪里有错。但是运行的结果却让我隐隐的感觉一定是哪里出错了,否则运行后在console输出中一定会有“hello this is mouse pressed!”。

我将上面的输出部分移动到draw函数中去,于是添加了draw函数,移入draw函数后代码运行的结果显示在了console中。
在这里插入图片描述

很奇怪,为何在keypress中就不行呢?我不信我的代码有问题,再次将draw中的这行输出代码剪切到keypressed函数中,非常惊奇的发现,这次keypressed函数中的代码运行了,一模一样没有改变。

在这里插入图片描述
如果要说改变,那么就是在整个代码中增加了draw函数。难道说,draw函数是keypressed函数赖以运行的基础???抱着试试的心态,我把draw函数删除,果然,程序运行后keypressed中的代码没有运行,console中没有输出hello this is mouse pressed!

综上所述,对于完整模式来说,setup和draw函数是必须的。而且,我们必须知道setup只运行一次,draw会按照某种频率来不停循环运行。

二、图形的刷新与绘制
1、图形刷新
在完整模式下,绘图的语句一般都放置在draw函数中,而且draw函数是反复循环的,当然,这个循环的频率是可以控制的,控制的方法是在setup中调用frameRate函数。我们来看看例子,我们按住ctrl+shift+O,打开processing的实例库,并在库中找到余弦波的动态图列子,如下图:
在这里插入图片描述
双击即可调入代码,通过运行我们发现这个图是动态的,屏幕会显示一个波动的余弦波。如下图:
在这里插入图片描述
我们为了满足某种需要,可能需要这个波动更慢或者更快,那么怎么办呢?
我们可以在setup中加入如frameRate的调用,代码如下:
在这里插入图片描述
frameRate默认的频率是60,这里我们设置为400,图形会运动的更快。
2、图形的绘制
a、绘图准备
绘图之前,我们必须准备一个画布,那么和我们在VC,QT,java中都一样,不同的是VC中可能需要绘图设备的准备,QT及java就会要求准备一个Qpainter。我们这里会更简单,直接进入绘图画布的准备,方法是直接调用一个size函数,设置高和宽即可(这个画布和VC 及QT中一样都是原点坐标在左上角)。比如我们设置一个400X300的画布,并且绘制一条线,可以在setup中这么简单的实现:
void setup()
{
/绘制一条线/

size(400,300); //设置画布大小
background(0); //设置背景颜色
stroke(255); //设置线条的颜色(这里是灰度),颜色可用RGB三个参数来设置
line(0,0,200,150);

}
运行效果如下:
在这里插入图片描述
需要注意的是,这里我们只是在setup中绘制了一条线,这条线只会被绘制一次。后面如果draw中的语句也在这块区域绘制图形,则这个图形就会被覆盖。如果要保证不覆盖,我们还是应该在draw中绘制。

b、draw函数中语句以及draw的作用
前面提到过,如果没有draw函数,我们的keypressed和mousePressed是不能正常运行的。特别需要指出的是draw函数中的语句是会按照frameRate所设置的频率来循环绘制的,所以draw函数中适合绘制动态图形。
比如,我们绘制一个跟随鼠标运动的原型,这个时候就必须把绘制的语句放置在draw函数中了。代码如下:

void setup()
{
   /*绘制一条线*/
   
   size(400,300);                //设置画布大小
   background(0);                //设置背景颜色
  // stroke(255);                  //设置线条的颜色(这里是灰度),颜色可用RGB三个参数来设置
  // line(0,0,200,150);

}

void draw()
{
  
   ellipse(mouseX,mouseY,50,50); //绘制一个圆,原点坐标随鼠标位置变化
   
}

在这里插入图片描述

我们在上面看到了一条重影(残影)的长管子,这就是因为我们没有及时擦去前面一帧留下的图形,我们将frameRate设置为2,这个时候会得到零星分布在画布上的圆:
在这里插入图片描述
当然,这里的终点不是讨论frameRate,我们要解决重影,需要及时擦去背景,那么在代码中加入background的设置即可。代码如下:

void setup()
{
   /*绘制一条线*/
   
   size(400,300);                //设置画布大小
   background(0);                //设置背景颜色
  // stroke(255);                  //设置线条的颜色(这里是灰度),颜色可用RGB三个参数来设置
  // line(0,0,200,150);
  //frameRate(2);
}

void draw()
{
   background(0);
   ellipse(mouseX,mouseY,50,50); //绘制一个圆,原点坐标随鼠标位置变化
   
}

b、2D与3D绘图的模式设定
在processing中绘制的图形分为2D和3D两种,在我写的processing摸索前行(1)中曾绘制过一个三维图形就是3d模式,那么在我们需要使用3d模式绘图时,需要在准备画布的时候就设定好,如我们要绘制一个圆球:

void setup()
{
   /*绘制一条线*/
   
   size(400,300,P3D);            //设置3D画布大小
   background(0);                //设置背景颜色
  
}

void draw()
{
   background(0);
   translate(200,150,0);        //设置三维图形的空间位置
   sphere(50); 
   
}

运行效果如下:
在这里插入图片描述
c、一些常用的绘制功能
除了在绘图时要绘制一些典型的几何图形外,我们有时候还需要用到绘制文字绘制图片,这里也来试试,首先我们来加载一个图片:


PImage img;                       //声明一个图形变量
void setup()
{
   /*绘制一条线*/
   
   size(400,300);                //设置3D画布大小
   background(0);                //设置背景颜色
   img=loadImage("face.jpg");//加载图形
}

void draw()
{
   background(0);
   image(img, 0, 0);             //从原点(0,0)处以图形原大小加载  
 
   
}

运行效果:
在这里插入图片描述
当如,如果我们要在上面写几个字的话,就要用到text函数:


PImage img;                       //声明一个图形变量
void setup()
{
   /*绘制一条线*/
   
   size(400,300);                //设置3D画布大小
   background(0);                //设置背景颜色
   img=loadImage("face.jpg");//加载图形
}

void draw()
{
   background(0);
   image(img, 0, 0);             //从原点(0,0)处以图形原大小加载  
   textFont(20)			   //设置字体大小
   text("显示图片案例",20,20);   //显示文字,从20,20位置开始输出文字
    
}

运行效果如下:
在这里插入图片描述

当然,还有很多的具体的绘图函数,我们不做一一列举,我们可以在Reference中查看具体的用法。

三、事件函数调用
在Reference中我们可以找到很多的事件,这里我们最关心的莫过于有互动效果的两个,即按键事件和鼠标事件。这里须重点强调的是在调用这些事件函数前须将draw函数实现,也就是说,一定要在代码中有draw的函数体。

1、按键事件
我们可以通过键值来判断具体按了哪个键,如果我们不加判断,那么任意按键都会在这个函数中被响应。这里需要介绍的是 keyPressed函数和keyType函数。
首先我们来看看,keyPressed函数和key以及keyCode的使用,这里我们来实现一个小游戏,按上下左右键,白球向上下左右运动,按任意其他键,小球停止运动,代码如下:

int direction;
float px,py;
void setup()
{
   size(600,300);
  
   px=width/2;
   py=height/2;
   

}

void draw()
{  
  
  background(0);
  switch(direction)
  {
     case UP:
     --py;
     drawCircle(px,py);
     break;
     case DOWN:
     ++py;
     drawCircle(px,py);
     break;
     case LEFT:
     --px;
     drawCircle(px,py);
     break;
     case RIGHT:
     ++px;
     drawCircle(px,py);
     break;
     default:
      py=py;
      px=px;
     drawCircle(px,py);
     break;
     
  
  }

}

void keyPressed()
{
  
  if (key == CODED) {
  print("key pressing now:");
  
  switch(keyCode){
   case UP:
    direction=keyCode;
    println("UP key is pressed!");
    break;
   case DOWN:
   direction=keyCode;
      println("DOWN key is pressed!");
    break;
   case LEFT:
   direction=keyCode;
      println("LEFT key is pressed!");
    break;
   case RIGHT:
   direction=keyCode;
      println("RIGHT key is pressed!");
    break;
   default:
   break;
   }
  }
  else
  {
  direction=0;
   println("PAUSE key is pressed!");
  }
     
}

void drawCircle(float x,float y)
{
    ellipse(x,y,50,50);
}

运行效果如下图(这里是静态图,运行程序可以得到动态图)
在这里插入图片描述
这里需要注意的是,keyCode只包含了UP, DOWN, LEFT, RIGHT ALT, CONTROL, SHIFT几个键;其余的需要通过key的值,即ASCII来判断;
keyReleased函数的用法和keyPressed没有什么差别,这里不再赘述;
keyType函数与keyPressed的区别在于,它屏蔽了几个功能键 Ctrl, Shift, Alt,CapsLock,以及四个方向键,也就是说,他们几个的按键事件不会在keyTyped中有任何反应。

2、鼠标事件

和按键事件一样,我们可以通过键值来判断具体按了哪个鼠标键,如果我们不加判断,那么任意鼠标按键都会在这个函数中被响应。典型的鼠标事件有mousePressed,mouseReleased,mouseWheel ,mouseDragged,mouseMoved。鼠标事件主要依靠mouseX,mouseY,以及mouseButton(这是个枚举值,有LEFT, RIGHT, CENTER三个选项)
下面我们通过鼠标在屏幕上画直线的小程序来演示他们的使用(点击开始画线,再次点击结束画线),代码如下:


float startX,startY,endX,endY;
int mouseState=0,endraw=0;


void setup()
{
   size(600,400);
   background(255);
   


}

void draw()
{
  background(255);
 
    if(endraw==1)
   drawline(startX,startY,endX,endY);

}

//获得起点坐标mouseState设置为1,按下
void mousePressed() 
{
  if(mouseButton==LEFT && mouseState==0 )
  {
     println("begin drawing line.");
      startX=mouseX;
      startY=mouseY;
      mouseState=1;  //它使mouseMoved能够更新终点坐标
      endraw=0;
    
  }
  else
   mouseState=0;    //使终点坐标不再更新(起点坐标没有LEFT的配合也不能更新)
   //(这里可以考虑添加存储已有线条的数据的代码)
   
}

//确认拖拽是否激活
void  mouseMoved()
{
 
    if(  mouseState>0 )
    {
      endraw=1;    //它使画线能够更新
      endX=mouseX;
      endY=mouseY;
    }


}



void drawline(float sx,float sy,float ex,float ey)
{
  line(sx,sy,ex,ey);
  println(mouseState+"start:"+startX+":"+startY+"end:"+endX+":"+endY);
}

运行效果如下:
在这里插入图片描述
以上程序仅仅实现了绘制单根线条,如果想在屏幕上同时显示多根线条,须将绘制的线条数据保存起来,每次在绘制的时候都将他们绘制出来即可。我们在以后的摸索中将会展示多线条的绘制。

既然是摸索,可能很多问题在Processing的官网上或者在他的documents中都已经详细说明了,但我必须说明的是,我这里是摸索,而不是按照既定的说明和教程在学习。所以出现了文章一开始遇到的问题。

如果您是通过搜索引擎来到了本页而没有了解前面的内容,可以点击下面的链接回顾前面的内容:
Processing摸索前行(1)
已经继续一起摸索后续的内容,
Processing摸索前行(3)

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河西石头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值