查看原文
其他

写给设计师的趣味编程指南7(Processing篇)- 程序流程控制-条件语句 (下)

2016-07-10 Wenzy InsLab

在窗口显示文字

这节的最终目标是完成一个文字冒险游戏,所以要先了解如何在程序中显示文字以及图片。之前输出的文字都在控制台上。但当我们导出程序的时,实际上是看不到控制台的。需要想办法把文字显示在窗口中。

显示文字的简便方式

如果你对字体的样式没有要求,只需用一个命令就能实现显示效果

代码示例(7-1):

void setup(){  size(400,400); } void draw(){  background(0);  text("Font is here",50,50);  text("字体在这里",50,150); }


调用格式:

text(str,x,y);
  • text 函数的作用是在窗口绘制字体。参数 str 写的就是文字内容,一般使用字符串类型,所以需要打上双括号以表明变量类型。除此之外也可以写整形,浮点型等数据。

  • 参数 x , y 代表的是字体显示的横纵坐标。这个坐标会决定字符左下角顶点的位置。

  • 英文字符是可以直接输入,但当你尝试往 text 函数中输入中文字符时会发现,Processing 中无法直接输入中文。你只能通过粘贴的办法。例如先在 txt 文档中输好中文,再复制过去

  • 有时复制后的中文会出现无法正常显示的情况,这时你可以在菜单栏选择 Processing - Preference


    在字体一栏选择一个支持显示中文的字体,如 Andale Mono,同时再将 Enable complex text input 勾选上。就能正常显示。

直接使用 text 命令,字体会设置为默认大小。如果你希望在窗口显示一些变量数据,而不是控制台,就可以采用这种省事的方式。

设置字体大小

代码示例(7-1-1):

void setup(){  size(400,400); } void draw(){  background(0);  textSize(50);  text("Font is here",50,50);  text("字体在这里",50,150); }


使用 textSize 函数可以用于设置字体大小。但只适用于英文字体,中文字体只能通过另外方式来设置。

显示中文字

Processing 中显示中文略微有点繁琐,但一旦搞清楚,后面使用起来还算比较方便。它主要通过 createFont 命令来创建字体。

代码示例(7-2):

PFont font; void setup(){   size(700,700);   font = createFont("SourceHanSansCN-Medium",30); } void draw(){  background(0);  textFont(font, 100);  text("中文字体", mouseX,mouseY); }


代码说明:

  • 第一句表示声明一个 PFont 类型,它就像 int ,float。只是它储存的不是数字,而是字体。后面的 font 代表变量名,是可以任意取的。

  • 创建了 PFont 类型,就相当于有了一个容器。我们需要告诉程序,这个容器里面存放什么。setup 中的 createFont()函数,就代表往 font 中载入一个名为”SourceHanSansCN-Medium”的字体。这是一个中文字体-思源黑体。第二个参数会决定字体的大小,但经过实际测试,此数值并没有很大的影响,后面有其他的函数会取代它。这里可以先填 30。

有人会有疑惑,如何找到这个名为“SourceHanSansCN-Medium”的字体?怎样能知道自己想用的字体叫什么名字?


你可以在 createFont 函数上右键,选 Find in Reference 查看官网的文档说明(当你想详细了解某个函数用法,这招十分好用)。


上面提到一个方法,只需加入两句命令,就能在控制台中输出系统包含的所有字体。


之后你只要复制对应的字符到 createFont 命令中即可。到这一步,如何你还不清楚这些英文字符所对应的字体,那可以在字体册中进行搜索。


  • 继续回到代码,draw 中的 textFont 函数,起的是设置的作用。它代表使用变量 font 中载入的字体来显示。而第二个参数,代表的是字体的大小,这里以像素为单位。

  • 之后再使用 text 函数,就能正常显示中文字体

改变字体颜色

可以将字体看作图形,它就像 ellipse 或是 rect,通过 fill 就能控制字体的颜色。

代码示例(7-3):

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); }


在窗口显示图片

与创建字体类似,也有专门为图片打造的数据类型。在程序中载入图片之前,我们需要先把图片文件放在对应的文件夹中。

在菜单栏上选择“速写本(Sketch)” - “打开程序目录(Show sketch folder),图片可以直接放在里面,与后缀为 pde 的源文件同级。

准备完毕后,就可以开始写代码

代码示例(7-4):

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); }


代码说明:

  • PImage 是用于存放图片的数据类型。

  • loadImage 函数的作用是载入图片“test.jpg”。

  • imageMode(CENTER); 设置图片的显示模式,若不加。图片的绘制方式则与矩形默认的绘制方式一致,坐标为左上角的顶点。开启此命令后,坐标则会居于图片中心

  • 函数 image() 的作用是显示图片。它有多种参数输入方式。可以添 3 个参数或是 5 个参数。当参数数量为 3 时,第一个参数填写 PImage 变量,第二,第三参数决定图片的横纵坐标。此时源图片的尺寸有多大,绘制到窗口中就有多大。当参数数量为 5 时,前 3 个参数与参数数量为 3 时完全一致,但后两个参数可以决定图片的长宽。

设置图片颜色

代码示例(7-5):

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); }


代码说明:

  • 这里载入的图片格式是带有透明背景的 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 就能归到此列。如果你是个掌机控,你肯定也听说过逆转裁判系列,它们都是文字冒险游戏中的优秀作品。


if 语句提供了建造程序骨架的可能性,现在你需要寻找“血肉”,将它们依附到骨架之上。如果你希望自己构建的世界更有代入感,图片素材是不可或缺的。请在编码前准备好相关的素材。

即使你既不会画画,也不懂设计,不代表就无法做游戏。不仅是代码,网上其实也有不少游戏美术资源是开源的,并且允许运用到个人作品或者商业作品中。例如 。以下程序用到的图片素材都来源于此。

  • 美术资源链接:

(终极Boss)
(森林背景)
(宝藏)
(骷髅)
(药瓶)

  • 字体:思源黑体,Adobe与谷歌推出开源字体。

我们先来看看实例的最终效果:


看上去已经比较唬人了,但以下代码都没有超出前面的知识。

代码示例(7-6):

PFont font; int count; PImage background, bottle, boss, bone, gold; void setup() {  size(700, 400);  font = createFont("SourceHanSansCN-Medium", 50);  bottle = loadImage("bottle.png");  background = loadImage("background.png");  boss = loadImage("boss.png");  bone = loadImage("bone.png");  gold = loadImage("gold.png");  count = 0; } void draw() {  background(0);  textFont(font, 50);  textSize(20);  //绘制背景  fill(255);  imageMode(CENTER);  image(background, width/2, height/2, 700, 400);  //绘制文字后的半透明背景  fill(0, 150);  rect(0, 250, 700, 80);  rect(0, 350, 700, 40);  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);    fill(255);    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);    fill(255);    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);    fill(255);    image(boss, width/2, height/3, 100, 100);  }  if (count == 4) {    fill(255, 0, 0);    imageMode(CENTER);    image(background, width/2, height/2, 700, 400);    fill(255);    text("你的速度太慢了,Boss 向你扔了一个火球", 30, 280);    text("由于实力的差距,你无法抵挡.....", 30, 310);    fill(150, 150, 255);    text("游戏结束", 30, 380);    fill(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);    fill(255);    image(gold, width/2, height/3, 170, 150);  }  if (count == 6) {    fill(255, 0, 0);    imageMode(CENTER);    image(background, width/2, height/2, 700, 400);    fill(255);    text("Boss 拒绝你的请求,并向你扔了个火球", 30, 280);    text("由于实力的差距,你无法抵挡.....", 30, 310);    fill(150, 150, 255);    text("游戏结束", 30, 380);    fill(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 进行决战。

  • 给场景配上战斗动画


导出作品

当你完成一个类似的游戏后,肯定想迫不及待地希望分享给其他人。从Processing 中导出程序十分简单。只要在菜单栏选择  文件(File) - 输出程序(Export Application)。


接着勾选输出平台,就能生成可执行文件。这个文件可以拷贝给其他人,它就像普通程序一样,只要打开就能运行。其他用户无需安装 Processing 也能正常使用。

End

希望这节能激起你的创作欲望,代码世界中会有更多精彩的事物留待你去挖掘~


点击阅读原文可获取示例 7-6 源码

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存