查看: 4482|回复: 3

[入门教程] 趣味编程指南(6-2)-程序的流程控制-判断语句2

[复制链接]
本帖最后由 kaka 于 2017-8-18 08:25 编辑

184156dg6igfyhdllluc88.jpg
KeyPressed 事件
现在相信你已经理解 if 的特性了。但要让它更好玩,你还需要用到后面介绍的一些编程概念。接着要介绍的,就是 keyPressed 事件。
前面与程序发生交互,基本上都是靠鼠标坐标 mouseX,mouseY 来实现的。虽然灵活,但局限性也很明显。当我们想通过鼠标位置来做选择的时候,就得写许多许多的if。在还没掌握如何写一个按钮控件的情况下。用键盘来做交互才是最明智的方式。
keyPressed 是与键盘相关的事件。它和 setup,draw 一样。在程序中已经事先定义好。你只需要把它的结构写进去,就能直接调用。
调用格式:
[AppleScript] 纯文本查看 复制代码
void keyPressed(){

}

2.png
keyPressed 可以暂且理解为与 setup,draw 是“同级”的。它独立于 setup,draw 之外。当你按下键盘上的按键,keyPressed 中填写的语句才会被执行。
下面先通过一个示例,理解 keyPressed 对程序流程的影响。
keyPressed 的运行流程
代码示例(6-14):
[AppleScript] 纯文本查看 复制代码
void setup(){
  println(frameCount + ":setup");
}

void draw(){
  println(frameCount + ":draw");
}

void keyPressed(){
  println(frameCount + ":keyPressed");
}

代码说明:
  • 运行程序后,记得在键盘上任意按下一些键,然后关闭程序,查看控制台的输出
  • 这里主要观察各个结构的执行顺序,其中的 frameCount 可获取程序当前已运行的帧数。
3.png

  • 在控制台往下翻,寻找带有“keyPressed”的字符串。它的输出位置,取决于你的按键时间。在这个例子中就表示,程序运行到 90 帧,就触发了按键事件。
  • 通过观察 frameCount,不难发现 keyPressed 事件是在 draw 后才执行的。
  • 这里的 “+” 代表链接前后两个字符串。前面的 frameCount 尽管是整形数据,但在 P5 中会默认先将它转化成字符串类型,再作链接。最终输出到控制台上。
keyPressed 获取按键键值
keyPressed 不仅能判断你何时按下按键,通过获取 key 的值,还能知道具体按了哪个键。
代码示例(6-15):
[AppleScript] 纯文本查看 复制代码
void keyPressed() {
  if (key == '1') {
    println( 1 );
  }
  if (key == '2') {
    println( 2 );
  }
  if (key == '3') {
    println( 3 );
  }
  if (key == 'a') {
    println( 'a' );
  }
  if (key == 's') {
    println( 's' );
  }
  if (key == 'd') {
    println( 'd' );
  }
}

上面例子对数字键 1,2,3,以及字母 a,s,d 添加了按键检测。当你按下这几个键。就会在控制台输出对应的字符。key 是系统定义好的,它会自动获取你按下的键值。所以若想了解 key 是否为某个值时,判断条件就需要写成 if(key == 某值)。当你想检测的是数字键或是字母键,只要在数字或是字母的基础上加单引号即可。
keyPressed 控制图形
前面通过鼠标的位置,来控制图形的显示或是隐藏。现在可以改用 keyPressed 试试。
代码示例(6-16):
[AppleScript] 纯文本查看 复制代码
boolean show;

void setup() {
  size(700, 700);
}

void draw() {
  background(32, 48, 65);
  if (show) {
    fill(3, 240, 175);
    noStroke();
    ellipse(width/2, height/2, 200, 200);
  }
}

void keyPressed() {
  if (key == '1') {
    show = true;
  }
  if (key == '2') {
    show = false;
  }
}

4.gif
  • 绘图函数不能写在 keyPressed 中,只能通过创建一个布尔变量来作为中介。keyPressed 先影响布尔变量的值。从而 draw 函数中的 if 语句再根据此值来决定显示与否。
有关 keyPressed 的用法先介绍到这里,够用就好了。后面会有更多的篇幅去深入理解各样事件。
在窗口显示文字
这节的最终目标是完成一个文字冒险游戏,所以要先了解如何在程序中显示文字以及图片。之前输出的文字都在控制台上。但当我们导出程序的时候,实际上是看不到控制台的。现在要想办法把文字显示在窗口中。
Processing 中显示中文略微有点繁琐,但一旦搞清楚,后面使用还是比较方便的。它主要通过 createFont 命令来创建字体。
代码示例(6-17):
[AppleScript] 纯文本查看 复制代码
PFont font;

void setup(){
   size(700,700);
   font = createFont("SourceHanSansCN-Medium",30);
}

void draw(){
  background(0);
  textFont(font, 100);
  text("中文字体", mouseX,mouseY);
}

5.gif
代码说明:
  • 第一句表示声明一个 PFont 类型,它就像 int ,float。只是它储存的不是数字,而是字体。后面的 font 代表变量名,是可以任意取的。
  • 创建了 PFont 类型,就相当于有了一个容器。我们需要告诉程序,这个容器里面存放什么。setup 中的 createFont()函数,就代表往 font 中载入一个名为”SourceHanSansCN-Medium”的字体。这是一个中文字体,叫做思源黑体。第二个参数会决定字体的大小,但经过实际测试,并没有很大的影响,后面有其他的函数会取代它。这里可以先填 30。
有人会问,那如何找到这个名为“SourceHanSansCN-Medium”的字体?我怎么知道自己想用的字体叫什么名字?
6.png
你可以在 createFont 函数上右键,选 Find in Reference 查看官网的文档说明(当你想详细了解某个函数用法,这招十分好用)。
7.png
上面提到一个方法,只需加入两句命令,就能在控制台中输出系统包含的所有字体。
8.png
之后你只要复制对应的字符到 createFont 命令中即可。到这一步,如何你还不清楚这些英文字符所对应的字体,那可以在字体册中进行搜索。
9.png
  • 继续回到代码,draw 中的 textFont 函数,起的是设置的作用。它代表使用变量 font 中载入的字体来显示。而第二个参数,代表的是字体的大小,这里以像素为单位。
  • draw 中的 text 函数是真正的执行部分,第一个参数填写字符显示的内容,第二第三个参数填写字符的横纵坐标。这个坐标决定字符的左下角所处的位置。
  • 当你尝试往 text 函数中输入中文字符时会发现,Processing 是无法直接输入中文的。你只能通过粘贴的办法。例如先在 txt 文档中输好中文,再复制过去。但有时复制后会出现仍然无法正常显示的情况,这时你可以在菜单栏选择 Processing - Preference
10.png


在字体一栏选择一个支持显示中文的字体,如 Andale Mono,同时再将 Enable complex text input 勾选上。就能正常显示。
改变字体颜色
可以将字体看作形状,通过 fill 就能控制字体的颜色。
代码示例(6-18):
[AppleScript] 纯文本查看 复制代码
PFont font;

void setup() {
  size(700, 700);
  font = createFont("SourceHanSansCN-Medium", 30); 
}

void draw() { 
  background(255);
  textFont(font, 100);
  fill(125);
  text("中文字体", 150, 300);

  fill(255, 155, 100);
  text("English", 150, 500);
}

11.jpg
在窗口显示图片
与创建字体类似,也有专门为图片打造的数据类型。在程序中载入图片之前,我们需要先把图片文件放在对应的文件夹中。
在菜单栏上选择“速写本(Sketch)” - “打开程序目录(Show sketch folder),图片可以直接放在里面,与后缀为 pde 的源文件同级。
准备完毕后,就可以开始写代码
代码示例(6-19):
[AppleScript] 纯文本查看 复制代码
PImage pic;

void setup(){
   size(700,700);
   pic = loadImage("test.jpg");
}

void draw(){ 
  background(200);
  imageMode(CENTER);
  image(pic,width/2,height/2,400,400);
}

12.png


代码说明:
  • PImage 是用于存放图片的数据类型。
  • loadImage 函数的作用是载入图片“test.jpg”。
  • imageMode(CENTER); 设置图片的显示模式,若不加。图片的绘制方式则与矩形默认的绘制方式一致,坐标为左上角的顶点。开启此命令后,坐标则会居于图片中心
  • 函数 image() 的作用是显示图片。它有多种参数输入方式。可以添 3 个参数或是 5 个参数。当参数数量为 3 时,第一个参数填写 PImage 变量,第二,第三参数决定图片的横纵坐标。此时源图片的尺寸有多大,绘制到窗口中就有多大。当参数数量为 5 时,前 3 个参数与参数数量为 3 时完全一致,但后两个参数可以决定图片的长宽。
设置图片颜色
代码示例(6-20):
[AppleScript] 纯文本查看 复制代码
PImage pic;

void setup(){
   size(700,700);
   background(255);
   pic = loadImage("dog.png");
}

void draw(){ 
  imageMode(CENTER);
  tint(mouseX/(float)width * 255,255,255);
  image(pic,mouseX,mouseY,200,200);
}

13.gif
代码说明:
  • 这里载入的图片格式是带有透明背景的 png。因此图片不会存在明显的矩形边框。
  • tint 可以设置图片的颜色。它决定的是图片每个通道的“放光”比例。假如图片某个像素的色值为(r,g,b,a),当使用 tint(A,B,C,D) 后,新像素的色彩就变为 (r * (A/255),g * (B/255),b * (C/255),a * (D/255))。tint 有点像一个滤镜,会对图片中的所有像素都进行同样的操作。当你不写 tint 时,程序默认执行 tint(255)。也就是百分百地还原图片的色彩。
  • 示例中通过 mouseX 来改变 tint 的第一个参数。就可以使红通道的放出量从 0% 变化到 100% 。当鼠标移到左方,红色光减少,绿蓝光就会显现。所以可以看到,doggy 的头像会呈现蓝绿色。
综合运用:文字冒险游戏
希望在开发游戏前,前面的基础知识都已经巩固好了。现在你已经具备制作一个文字冒险游戏的所有条件了。
文字冒险游戏是什么?前不久非常流行的 lifeLine 就能归到此列。如果你是个掌机控,你肯定也听说过逆转裁判系列,它们都是文字冒险游戏中的优秀作品。
14.jpg
15.jpg
if 语句提供了建造程序骨架的可能性,现在你需要寻找“血肉”,将它们依附到骨架之上。如果你希望自己构建的世界更有代入感,图片素材是不可或缺的。请在编码前搜集好相关的素材。
网上有许多游戏美术资源都是开源的,同时允许运用到个人作品或者商业作品中。
以下是程序中用到的字体和图片素材。
字体:思源黑体,Adobe与谷歌推出开源字体。
美术资源链接:
程序截图:
16.png
17.png
18.png
现在已经可以做些比较吓唬人的效果了,以下代码都没有超出前面的知识。
代码示例(6-21):
[AppleScript] 纯文本查看 复制代码
PFont font;
int count;
PImage background, bottle, boss, bone, gold;


void setup() {
  size(700, 400);
  bottle = loadImage("bottle.png");
  background = loadImage("background.png");
  boss = loadImage("boss.png");
  bone = loadImage("bone.png");
  gold = loadImage("gold.png");
  font = createFont("SourceHanSansCN-Medium", 200); 
  count = 0;
}

void draw() {
  background(0);
  textFont(font, 50);
  textSize(20);

  // 绘制背景
  fill(255);
  imageMode(CORNER);
  image(background, 0, 0, width, height);

  // 绘制文字后的半透明背景
  fill(0, 150);
  rect(0, 250, 700, 80);
  rect(0, 350, 700, 40);

  imageMode(CENTER);
  if (count == 0) {
    fill(255);
    text("你為了尋找傳說中的寶藏,进入了黑暗森林。", 30, 280);

    text("突然,你和你的小伙伴在路上看见一个神秘药瓶,你打算怎么做。", 30, 310);
    fill(150, 150, 255);
    text("1.踢飞它", 30, 380);
    text("2.自己喝了", 180, 380);
    text("3.怂恿小伙伴喝了", 330, 380);

    fill(255);
    image(bottle, width/2, height/3, 100, 100);
  }

  if (count == 1) {
    fill(255);
    text("水壶翻倒了,突然一股浓烟冒出。", 30, 280);
    text("终极 Boss 直接出现到面前 …(⊙_⊙;),你准备", 30, 310);
    fill(150, 150, 255);
    text("1.情况不妙,闪", 30, 380);
    text("2.我是勇者我进攻!", 240, 380);
    text("3.陪它聊聊天", 500, 380);
    image( boss, width/2, height/3, 100, 100);
  }

  if (count == 2) {

    fill(255);
    text("你感到力量无穷,同时受到宝藏的呼唤", 30, 280);
    text("直接来到了终极 Boss 的面前,你准备", 30, 310);
    fill(150, 150, 255);
    text("1.不啰嗦,直接进攻", 30, 380);
    text("2.陪它聊聊天", 250, 380);

    image(boss, width/2, height/3, 100, 100);
  }


  if (count == 3) {
    fill(255);
    text("小伙伴痛苦地跪倒在地上。", 30, 280);
    text("化身成终极 Boss 站到你的面前 …(⊙_⊙;),你准备", 30, 310);
    fill(150, 150, 255);
    text("1.情况不妙,闪", 30, 380);
    text("2.我是勇者我进攻!", 240, 380);
    text("3.陪它聊聊天", 500, 380);

    image(boss, width/2, height/3, 100, 100);
  }

  if (count == 4) {
    tint(255, 0, 0);
    imageMode(CORNER);
    image(background, 0, 0, width, height);
    fill(255);
    text("你的速度太慢了,Boss 向你扔了一个火球", 30, 280);
    text("由于巨大的实力差距,你挂了.....", 30, 310);
    fill(150, 150, 255);
    fill(150, 150, 255);
    text("游戏结束", 30, 380);

    imageMode(CENTER); 
    tint(255);
    image(bone, width/2, height/3, 100, 100);
  }

  if (count == 5) {
    fill(255);
    text("Boss 被你的气势打倒了", 30, 280);
    text("宝藏出现", 30, 310);
    fill(150, 150, 255);
    text("你和小伙伴带着宝藏逃离黑暗森林,通关成功!", 30, 380);
    image(gold, width/2, height/3, 170, 150);
  }

  if (count == 6) {
    tint(255, 0, 0);
    imageMode(CORNER);
    image(background, 0, 0, width, height);
    fill(255);
    text("Boss 拒绝你的请求,并向你扔了个火球", 30, 280);
    text("由于巨大的实力差距,你挂了.....", 30, 310);
    fill(150, 150, 255);
    text("游戏结束", 30, 380);

    imageMode(CENTER); 
    tint(255);
    image(bone, width/2, height/3, 100, 100);
  }
}

void keyPressed() {
  if (count == 0) {
    if (key == '1') {
      count = 1;
    }
    if (key == '2') {
      count = 2;
    }
    if (key == '3') {
      count = 3;
    }
  } else if (count == 1 || count == 3) {
    if (key == '1') {
      count = 4;
    }
    if (key == '2') {
      count = 5;
    }
    if (key == '3') {
      count = 6;
    }
  } else if (count == 2) {
    if (key == '1') {
      count = 5;
    }
    if (key == '2') {
      count = 6;
    }
  }
}

代码浅析:
  • 示例中只有两次选择机会
  • 示例展示的只是基本用法,留待你去扩展,补充
  • count 变量代表一个计数器。通过它来标记不同的场景。当触发不同的按键,就能在场景间进行跳转,draw 函数也会因应 count 的变化,绘制出对应的场景。
扩展
  • 用 string 简化代码
  • 尝试设计更复杂的分支结构。甚至给角色加上生命力,攻击力。与终极 Boss 进行决战。
  • 给场景配上战斗动画
19.gif




导出作品
当你完成一个类似的游戏后,肯定想迫不及待地希望分享给其他人。从Processing 中导出程序十分简单。只要在菜单栏选择 文件(File) - 输出程序(Export Application)。
20.png
接着勾选输出平台,就能生成可执行文件。这个文件可以拷贝给其他人,它就像普通程序一样,只要打开就能运行。其他用户无需安装 Processing 也能正常使用。


kaka  版主
 楼主|

发表于 2017-3-21 19:06:36

最近好忙啊,所以发慢了,也发少了,下个月一定补上
回复 支持 反对

使用道具 举报

iooops  版主

发表于 2017-3-22 18:50:05

kaka 发表于 2017-3-21 19:06
最近好忙啊,所以发慢了,也发少了,下个月一定补上

期待更新啊
回复 支持 反对

使用道具 举报

iooops  版主

发表于 2017-3-22 18:50:22

kaka 发表于 2017-3-21 19:06
最近好忙啊,所以发慢了,也发少了,下个月一定补上

楼主上干货啊
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
wifi气象站

硬件清单

btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2019 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail