Processing语言的最终指南第二部分(构建简单的游戏)

本文概述

  • Processing教程:一个简单的游戏
  • 构建蓬松乒乓球
  • 使用p5.js将Processing游戏代码移植到Web
  • Processing游戏代码:你也可以做
【Processing语言的最终指南第二部分(构建简单的游戏)】这是Processing语言最终指南的第二部分。在第一部分中, 我给出了基本的Processing语言演练。你学习下一步的过程就是更多的动手编程。
在本文中, 我将逐步向你展示如何使用Processing来实现自己的游戏。将详细说明每个步骤。然后, 我们将游戏移植到网络上。
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
在开始Processing教程之前, 这是上一部分DVD徽标练习的代码。如有任何疑问, 请务必发表评论。
Processing教程:一个简单的游戏 我们将在此Processing教程中构建的游戏是Flappy Bird, Pong和Brick Breaker的组合。我之所以选择这样的游戏, 是因为它具有初学者在学习游戏开发时会遇到的大多数概念。这是基于我担任助教以来的经验, 帮助新程序员学习如何使用Processing。这些概念包括重力, 碰撞, 保持分数, Processing不同的屏幕以及键盘/鼠标交互。 Flappy Pong拥有所有这些。
立即玩游戏!
如果不使用面向对象编程(OOP)的概念, 就很难构建复杂的游戏, 例如具有多个级别, 玩家, 实体等的平台游戏。随着我们的前进, 你将看到代码如何迅速变得复杂。我尽我所能使此” Processing” 教程井井有条且简单。
我建议你阅读本文, 获取完整的代码, 自己使用它, 开始尽快考虑自己的游戏, 并开始实施它。
让我们开始吧。
构建蓬松乒乓球 Processing教程步骤1:初始化和Processing不同的屏幕
第一步是初始化我们的项目。对于初学者, 我们将像往常一样编写设置和绘制块, 没有新奇或幻想。然后, 我们将Processing不同的屏幕(初始屏幕, 游戏屏幕, 游戏上方屏幕等)。因此出现了问题, 我们如何使Processing在正确的时间显示正确的页面?
完成此任务非常简单。我们将有一个全局变量, 用于存储当前活动屏幕的信息。然后, 我们根据变量绘制正确屏幕的内容。在绘制块中, 我们将具有一个if语句, 该语句检查变量并相应地显示屏幕内容。每当我们想要更改屏幕时, 我们都会将该变量更改为我们希望其显示的屏幕的标识符。这么说, 这就是我们的框架代码:
/********* VARIABLES *********/// We control which screen is active by settings / updating // gameScreen variable. We display the correct screen according // to the value of this variable. // // 0: Initial Screen // 1: Game Screen // 2: Game-over Screenint gameScreen = 0; /********* SETUP BLOCK *********/void setup() { size(500, 500); }/********* DRAW BLOCK *********/void draw() { // Display the contents of the current screen if (gameScreen == 0) { initScreen(); } else if (gameScreen == 1) { gameScreen(); } else if (gameScreen == 2) { gameOverScreen(); } }/********* SCREEN CONTENTS *********/void initScreen() { // codes of initial screen } void gameScreen() { // codes of game screen } void gameOverScreen() { // codes for game over screen }/********* INPUTS *********/public void mousePressed() { // if we are on the initial screen when clicked, start the game if (gameScreen==0) { startGame(); } }/********* OTHER FUNCTIONS *********/// This method sets the necessary variables to start the game void startGame() { gameScreen=1; }

乍一看, 这似乎很可怕, 但是我们所做的只是建立基本结构, 并用注释框分隔不同的部分。
如你所见, 我们为要显示的每个屏幕定义了不同的方法。在我们的绘制块中, 我们只需检查我们的gameScreen变量的值, 然后调用相应的方法。
在void mousePressed(){… }部分中, 我们正在监听鼠标单击, 如果活动屏幕为0(初始屏幕), 则调用startGame()方法, 该方法将按你期望的方式启动游戏。此方法的第一行将gameScreen变量更改为1, 即游戏屏幕。
如果可以理解, 那么下一步就是实施我们的初始屏幕。为此, 我们将编辑initScreen()方法。它去了:
void initScreen() { background(0); textAlign(CENTER); text("Click to start", height/2, width/2); }

现在, 我们的初始屏幕具有黑色背景和简单文本, 即” 单击以开始” , 位于中间并与中心对齐。但是, 当我们单击时, 什么也没有发生。我们尚未为游戏屏幕指定任何内容。方法gameScreen()中没有任何内容, 因此我们没有将background()作为第一行绘制内容来覆盖从最后一个屏幕(文本)中绘制的先前内容。这就是为什么文本仍然存在的原因, 即使不再调用text()行(就像最后一部分中留下痕迹的移动球示例一样)。出于相同的原因, 背景仍为黑色。因此, 让我们继续并开始实现游戏屏幕。
void gameScreen() { background(255); }

进行此更改后, 你会注意到背景变成白色并且文本消失。
Processing教程步骤2:创建球并实现重力
现在, 我们将开始在游戏屏幕上工作。我们将首先创建我们的球。我们应该为其坐标, 颜色和大小定义变量, 因为稍后可能需要更改这些值。例如, 如果我们想随着球手得分的增加而增加球的大小, 以使比赛变得更加困难。我们将需要更改其大小, 因此它应该是一个变量。在实现重力之后, 我们还将定义球的速度。
首先, 我们添加以下内容:
... int ballX, ballY; int ballSize = 20; int ballColor = color(0); ... void setup() { ... ballX=width/4; ballY=height/5; } ... void gameScreen() { ... drawBall(); } ... void drawBall() { fill(ballColor); ellipse(ballX, ballY, ballSize, ballSize); }

我们将坐标定义为全局变量, 创建了一个绘制球的方法, 称为gameScreen方法。这里唯一需要注意的是我们初始化了坐标, 但是我们在setup()中定义了它们。我们这样做的原因是我们希望球从左四分之一开始, 从顶部五分之一开始。我们并不需要特别的理由, 但这是开始发球的好方法。因此, 我们需要动态获取草图的宽度和高度。草图大小在第一行之后的setup()中定义。在运行setup()之前未设置width和height, 这就是为什么如果我们在顶部定义变量则无法实现这一点。
重力 现在实现重力实际上是容易的部分。只有几招。首先是实现:
... float gravity = 1; float ballSpeedVert = 0; ... void gameScreen() { ... applyGravity(); keepInScreen(); } ... void applyGravity() { ballSpeedVert += gravity; ballY += ballSpeedVert; } void makeBounceBottom(float surface) { ballY = surface-(ballSize/2); ballSpeedVert*=-1; } void makeBounceTop(float surface) { ballY = surface+(ballSize/2); ballSpeedVert*=-1; } // keep ball in the screen void keepInScreen() { // ball hits floor if (ballY+(ballSize/2) > height) { makeBounceBottom(height); } // ball hits ceiling if (ballY-(ballSize/2) < 0) { makeBounceTop(0); } }

结果是:
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
抱着你的马, 物理学家。我知道这不是重力在现实生活中的工作方式。相反, 这更多的是动画过程。我们定义为重力的变量只是一个数字值(一个浮点数, 以便我们可以使用十进制值, 而不仅仅是整数), 我们在每个循环中将其添加到ballSpeedVert中。 ballSpeedVert是球的垂直速度, 它在每个循环中被加到球的Y坐标(ballY)上。我们观察球的坐标并确保其停留在屏幕上。如果我们不这样做, 球会掉到无穷远。目前, 我们的球只垂直移动。因此, 我们观察屏幕的地板和天花板边界。使用keepInScreen()方法, 我们检查ballY(+半径)是否小于高度, 并且类似地ballY(-半径)大于0。如果不满足条件, 我们使球反弹(从底部开始)或顶部)与makeBounceBottom()和makeBounceTop()方法。要使球弹起, 我们只需将球移到必须弹起的确切位置, 然后将垂直速度(ballSpeedVert)乘以-1(乘以-1即可更改符号)。当速度值带有负号时, 将Y坐标加起来, 速度将变为ballY +(-ballSpeedVert), 即ballY-ballSpeedVert。因此, 球立即以相同的速度改变方向。然后, 当我们向ballSpeedVert中添加重力并且ballSpeedVert具有负值时, 它开始接近0, 最终变为0, 并再次开始增加。这会使球上升, 上升变慢, 停止并开始下降。
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
但是, 我们的动画Processing过程存在问题-球不断弹跳。如果这是现实情况, 则每次接触表面时, 球都会面临空气阻力和摩擦。这就是我们在游戏动画过程中想要的行为, 因此实现起来很容易。我们添加以下内容:
... float airfriction = 0.0001; float friction = 0.1; ... void applyGravity() { ... ballSpeedVert -= (ballSpeedVert * airfriction); } void makeBounceBottom(int surface) { ... ballSpeedVert -= (ballSpeedVert * friction); } void makeBounceTop(int surface) { ... ballSpeedVert -= (ballSpeedVert * friction); }

现在, 我们的动画过程产生了以下结果:
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
顾名思义, 摩擦是表面摩擦, 而空气摩擦是空气的摩擦。因此很明显, 每次球接触任何表面时都必须施加摩擦。然而, 空中摩擦必须不断应用。这就是我们所做的。 applyGravity()方法在每个循环上运行, 因此我们在每个循环上从ballSpeedVert中减去其当前值的0.0001%。当球接触任何表面时, makeBounceBottom()和makeBounceTop()方法将运行。因此, 在这些方法中, 我们只是做了一次相同的事情, 只是这次只是摩擦。
Processing教程步骤3:创建球拍
现在我们需要一个球拍来使球反弹。我们应该控制球拍。让我们用鼠标控制它。这是代码:
... color racketColor = color(0); float racketWidth = 100; float racketHeight = 10; ... void gameScreen() { ... drawRacket(); ... } ... void drawRacket(){ fill(racketColor); rectMode(CENTER); rect(mouseX, mouseY, racketWidth, racketHeight); }

我们将球拍的颜色, 宽度和高度定义为全局变量, 我们可能希望它们在游戏过程中发生变化。我们实现了一个方法drawRacket(), 该方法可以实现其名称所建议的功能。我们将rectMode设置为居中, 因此我们的球拍与光标的中心对齐。
现在我们创建了球拍, 我们必须在球上弹跳。
... int racketBounceRate = 20; ... void gameScreen() { ... watchRacketBounce(); ... } ... void watchRacketBounce() { float overhead = mouseY - pmouseY; if ((ballX+(ballSize/2) > mouseX-(racketWidth/2)) & & (ballX-(ballSize/2) < mouseX+(racketWidth/2))) { if (dist(ballX, ballY, ballX, mouseY)< =(ballSize/2)+abs(overhead)) { makeBounceBottom(mouseY); // racket moving up if (overhead< 0) { ballY+=overhead; ballSpeedVert+=overhead; } } } }

结果如下:
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
所以watchRacketBounce()要做的是确保球拍和球发生碰撞。这里有两件事要检查, 即球和球拍在垂直和水平方向上是否都对齐。第一个if语句检查球右侧的X坐标是否大于球拍左侧的X坐标(反之亦然)。如果是, 则第二条语句检查球和球拍之间的距离是否小于或等于球的半径(这意味着它们正在碰撞)。因此, 如果满足这些条件, 则将调用makeBounceBottom()方法, 并且球会在我们的球拍上反弹(在球拍所在的mouseY处)。
你是否注意到mouseY-pmouseY计算出的可变开销? pmouseX和pmouseY变量将鼠标的坐标存储在前一帧。由于鼠标可以非常快速地移动, 因此如果鼠标足够快地朝着球移动, 我们很有可能无法正确检测到帧之间球与球拍之间的距离。因此, 我们考虑了帧之间鼠标坐标的差异, 并在检测距离时将其考虑在内。鼠标移动得越快, 可接受的距离就越大。
我们还出于其他原因使用开销。我们通过检查开销的迹象来检测鼠标的移动方式。如果开销为负, 则鼠标位于前一帧的下方, 因此我们的鼠标(球拍)正在向上移动。在这种情况下, 我们希望为球增加一个额外的速度, 并将其移动到比常规弹跳稍远的位置, 以模拟用球拍击球的效果。如果开销小于0, 则将其添加到ballY和ballSpeedVert中, 以使球变得更高, 更快。因此, 球拍击球的速度越快, 它上升的速度就越高。
Processing教程步骤4:水平移动和控制球
在本节中, 我们将向球添加水平运动。然后, 我们将可以用球拍水平控制球。开始了:
... // we will start with 0, but for we give 10 just for testing float ballSpeedHorizon = 10; ... void gameScreen() { ... applyHorizontalSpeed(); ... } ... void applyHorizontalSpeed(){ ballX += ballSpeedHorizon; ballSpeedHorizon -= (ballSpeedHorizon * airfriction); } void makeBounceLeft(float surface){ ballX = surface+(ballSize/2); ballSpeedHorizon*=-1; ballSpeedHorizon -= (ballSpeedHorizon * friction); } void makeBounceRight(float surface){ ballX = surface-(ballSize/2); ballSpeedHorizon*=-1; ballSpeedHorizon -= (ballSpeedHorizon * friction); } ... void keepInScreen() { ... if (ballX-(ballSize/2) < 0){ makeBounceLeft(0); } if (ballX+(ballSize/2) > width){ makeBounceRight(width); } }

结果是:
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
这里的想法与我们进行垂直运动的想法相同。我们创建了一个水平速度变量ballSpeedHorizo??n。我们创建了一种将水平速度应用于ballX并消除空气摩擦的方法。我们向keepInScreen()方法添加了两个if语句, 该语句将观察球触及屏幕的左边缘和右边缘。最后, 我们创建了makeBounceLeft()和makeBounceRight()方法来Processing左右反弹。
现在我们为游戏增加了水平速度, 我们想用球拍控制球。就像在著名的Atari游戏Breakout和其他所有打砖块游戏中一样, 球应该根据球拍击中的点向左或向右移动。球拍的边缘应使球具有更高的水平速度, 而中间不应该有任何作用。代码优先:
void watchRacketBounce() { ... if ((ballX+(ballSize/2) > mouseX-(racketWidth/2)) & & (ballX-(ballSize/2) < mouseX+(racketWidth/2))) { if (dist(ballX, ballY, ballX, mouseY)< =(ballSize/2)+abs(overhead)) { ... ballSpeedHorizon = (ballX - mouseX)/5; ... } } }

结果是:
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
将该简单的行添加到watchRacketBounce()即可完成工作。我们要做的是使用ballX-mouseX确定球击中球拍中心的点的距离。然后, 将其设为水平速度。实际的差异太大, 因此我尝试了一下, 并认为十分之一的值是最自然的。
Processing教程步骤5:创建墙
我们的草图开始看起来更像游戏中的每一步。在这一步中, 我们将添加向左移动的墙, 就像在《飞扬的小鸟》中一样:
... int wallSpeed = 5; int wallInterval = 1000; float lastAddTime = 0; int minGapHeight = 200; int maxGapHeight = 300; int wallWidth = 80; color wallColors = color(0); // This arraylist stores data of the gaps between the walls. Actuals walls are drawn accordingly. // [gapWallX, gapWallY, gapWallWidth, gapWallHeight] ArrayList< int[]> walls = new ArrayList< int[]> (); ... void gameScreen() { ... wallAdder(); wallHandler(); } ... void wallAdder() { if (millis()-lastAddTime > wallInterval) { int randHeight = round(random(minGapHeight, maxGapHeight)); int randY = round(random(0, height-randHeight)); // {gapWallX, gapWallY, gapWallWidth, gapWallHeight} int[] randWall = {width, randY, wallWidth, randHeight}; walls.add(randWall); lastAddTime = millis(); } } void wallHandler() { for (int i = 0; i < walls.size(); i++) { wallRemover(i); wallMover(i); wallDrawer(i); } } void wallDrawer(int index) { int[] wall = walls.get(index); // get gap wall settings int gapWallX = wall[0]; int gapWallY = wall[1]; int gapWallWidth = wall[2]; int gapWallHeight = wall[3]; // draw actual walls rectMode(CORNER); fill(wallColors); rect(gapWallX, 0, gapWallWidth, gapWallY); rect(gapWallX, gapWallY+gapWallHeight, gapWallWidth, height-(gapWallY+gapWallHeight)); } void wallMover(int index) { int[] wall = walls.get(index); wall[0] -= wallSpeed; } void wallRemover(int index) { int[] wall = walls.get(index); if (wall[0]+wall[2] < = 0) { walls.remove(index); } }

结果是:
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
即使代码看起来冗长而令人生畏, 我保证没有什么很难理解的。首先要注意的是ArrayList。对于那些不知道ArrayList是什么的人来说, 它只是list的实现, 就像Array一样, 但是相对于它, 它有一些优势。它是可调整大小的, 具有有用的方法, 如list.add(index), list.get(index)和list.remove(index)。我们将墙数据保留为arraylist中的整数数组。我们保留在数组中的数据用于两堵墙之间的间隙。数组包含以下值:
[gap wall X, gap wall Y, gap wall width, gap wall height]

实际壁是根据间隙壁值绘制的。请注意, 使用类可以更好, 更简洁地Processing所有这些问题, 但是由于” 面向对象编程” (OOP)的使用不在本” Processing” 教程的范围之内, 因此我们将采用这种方式进行Processing。我们有两种管理墙壁的基本方法, wallAdder()和wallHandler。
wallAdder()方法仅在每个wallInterval毫秒内将新的墙添加到arraylist中。我们有一个全局变量lastAddTime, 它存储添加最后一堵墙的时间(以毫秒为单位)。如果当前毫秒millis()减去最后添加的毫秒lastAddTime大于我们的间隔值wallInterval, 则意味着现在该添加一个新的墙了。然后根据最顶部定义的全局变量生成随机间隙变量。然后将新的墙(存储间隙墙数据的整数数组)添加到arraylist中, 并将lastAddTime设置为当前毫秒millis()。
wallHandler()循环遍历arraylist中的当前墙。对于每个循环中的每个项目, 它通过arraylist的索引值调用wallRemover(i), wallMover(i)和wallDrawer(i)。这些方法如其名称所示。 wallDrawer()根据间隙壁数据绘制实际的壁。它从arraylist中获取墙数据数组, 并调用rect()方法将墙绘制到实际位置。 wallMover()方法从arraylist中获取元素, 并根据wallSpeed全局变量更改其X位置。最后, wallRemover()从arraylist中移除屏幕之外的墙。如果我们不这样做, 那么Processing程序将把它们视为仍在屏幕中。那将是巨大的性能损失。因此, 当从阵列列表中删除墙时, 它不会在后续循环中绘制。
最后要做的挑战性工作是检测球与墙壁之间的碰撞。
void wallHandler() { for (int i = 0; i < walls.size(); i++) { ... watchWallCollision(i); } } ... void watchWallCollision(int index) { int[] wall = walls.get(index); // get gap wall settings int gapWallX = wall[0]; int gapWallY = wall[1]; int gapWallWidth = wall[2]; int gapWallHeight = wall[3]; int wallTopX = gapWallX; int wallTopY = 0; int wallTopWidth = gapWallWidth; int wallTopHeight = gapWallY; int wallBottomX = gapWallX; int wallBottomY = gapWallY+gapWallHeight; int wallBottomWidth = gapWallWidth; int wallBottomHeight = height-(gapWallY+gapWallHeight); if ( (ballX+(ballSize/2)> wallTopX) & & (ballX-(ballSize/2)< wallTopX+wallTopWidth) & & (ballY+(ballSize/2)> wallTopY) & & (ballY-(ballSize/2)< wallTopY+wallTopHeight) ) { // collides with upper wall }if ( (ballX+(ballSize/2)> wallBottomX) & & (ballX-(ballSize/2)< wallBottomX+wallBottomWidth) & & (ballY+(ballSize/2)> wallBottomY) & & (ballY-(ballSize/2)< wallBottomY+wallBottomHeight) ) { // collides with lower wall } }

watchWallCollision()方法在每个循环中的每个墙都被调用。我们获取间隙壁的坐标, 计算实际壁(顶部和底部)的坐标, 然后检查球的坐标是否与壁碰撞。
Processing教程步骤6:运行状况和评分
现在我们可以检测到球和墙壁的碰撞, 我们可以决定游戏的机制了。在对游戏进行了一些调整之后, 我设法使游戏具有一定的可玩性。但是, 这仍然非常困难。我对游戏的第一个想法是使它像《飞扬的小鸟》, 当球碰到墙壁时, 游戏结束。但是后来我意识到这是不可能的。所以这就是我的想法:
球顶应该有一个健康栏。球碰壁时应该失去健康。按照这种逻辑, 让球从墙壁弹回是没有意义的。因此, 当运行状况为0时, 游戏应该结束, 并且我们应该通过屏幕切换到游戏。所以我们开始:
int maxHealth = 100; float health = 100; float healthDecrease = 1; int healthBarWidth = 60; ... void gameScreen() { ... drawHealthBar(); ... } ... void drawHealthBar() { // Make it borderless: noStroke(); fill(236, 240, 241); rectMode(CORNER); rect(ballX-(healthBarWidth/2), ballY - 30, healthBarWidth, 5); if (health > 60) { fill(46, 204, 113); } else if (health > 30) { fill(230, 126, 34); } else { fill(231, 76, 60); } rectMode(CORNER); rect(ballX-(healthBarWidth/2), ballY - 30, healthBarWidth*(health/maxHealth), 5); } void decreaseHealth(){ health -= healthDecrease; if (health < = 0){ gameOver(); } }

这是一个简单的运行:
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
我们创建了一个全局变量健康状况, 以保持健康状态。然后创建方法drawHealthBar()在球的顶部绘制两个矩形。第一个是基本运行状况栏, 第二个是显示当前运行状况的活动栏。第二个控件的宽度是动态的, 并使用healthBarWidth *(health / maxHealth)(我们当前的健康状况相对于健康条宽度的比率)进行计算。最后, 根据健康值设置填充颜色。最后但并非最不重要的是, 得分:
... void gameOverScreen() { background(0); textAlign(CENTER); fill(255); textSize(30); text("Game Over", height/2, width/2 - 20); textSize(15); text("Click to Restart", height/2, width/2 + 10); } ... void wallAdder() { if (millis()-lastAddTime > wallInterval) { ... // added another value at the end of the array int[] randWall = {width, randY, wallWidth, randHeight, 0}; ... } } void watchWallCollision(int index) { ... int wallScored = wall[4]; ... if (ballX > gapWallX+(gapWallWidth/2) & & wallScored==0) { wallScored=1; wall[4]=1; score(); } } void score() { score++; } void printScore(){ textAlign(CENTER); fill(0); textSize(30); text(score, height/2, 50); }

我们需要在球经过墙时得分。但是我们需要为每堵墙添加最大1分。意思是, 如果球越过一堵墙然后又越过一堵墙, 则不应添加其他得分。为了实现这一点, 我们在arraylist的间隙壁数组中添加了另一个变量。如果球还没有越过那堵墙, 新变量将存储0;如果球还没有越过该墙, 则新变量将存储1。然后, 我们修改了watchWallCollision()方法。我们添加了一个条件, 当球通过之前从未通过的墙时, 它会触发score()方法并将墙标记为已通过。
我们现在快结束了。最后要做的是在屏幕上的游戏上单击重新启动。我们需要将所有使用过的变量设置为其初始值, 然后重新启动游戏。这里是:
... public void mousePressed() { ... if (gameScreen==2){ restart(); } } ... void restart() { score = 0; health = maxHealth; ballX=width/4; ballY=height/5; lastAddTime = 0; walls.clear(); gameScreen = 0; }

让我们添加更多颜色。
Processing语言的最终指南第二部分(构建简单的游戏)

文章图片
瞧!我们有蓬松的乒乓球!
完整的《 Processing》游戏代码可在此处找到。
使用p5.js将Processing游戏代码移植到Web p5.j??s是一个JavaScript库, 其语法与Processing编程语言非常相似。它不是一个能够简单运行现有Processing代码的库;相反, p5.js需要编写实际的JavaScript代码-类似于Processing的JavaScript端口, 即Processing.js。我们的任务是使用p5.js API将Processing代码转换为JavaScript。该库具有一组类似于Processing的函数和语法, 并且我们必须对代码进行某些更改才能使其在JavaScript中工作-但由于Processing和JavaScript与Java都具有相似之处, 因此这听起来并不容易。 。即使你不是JavaScript开发人员, 所做的更改也是微不足道的, 你应该可以很好地遵循。
首先, 我们需要创建一个简单的index.html并将p5.min.js添加到我们的标头中。我们还需要创建另一个名为flappy_pong.js的文件, 该文件将存储我们转换后的代码。
< html> < head> < title> Flappy Pong< /title> < script tyle="text/javascript" src="http://img.readke.com/220519/0F02TX1-10.jpg"> < /script> < script tyle="text/javascript" src="http://www.srcmini.com/flappy_pong.js"> < /script> < style> canvas { box-shadow: 0 0 20px lightgray; } < /style> < /head> < body> < /body> < /html>

转换代码时, 我们的策略应该是将所有代码复制并粘贴到flippy_pong.js中, 然后进行所有更改。这就是我所做的。这是我更新代码所采取的步骤:
Javascript是一种无类型的语言(没有int和float这样的类型声明)。因此, 我们需要将所有类型声明更改为var。
Javascript中没有空白。我们应该改变所有功能。
我们需要从函数签名中删除参数的类型声明。 (即void wallMover(var index){to function wallMover(index){)
JavaScript中没有ArrayList。但是我们可以使用JavaScript数组实现相同的目的。我们进行以下更改:
  • ArrayList < int []> 墙=新的ArrayList < int []> (); 到var墙= [];
  • wall.clear(); 到墙壁= [];
  • wall.add(randWall); 到walls.push(randWall);
  • wall.remove(index); 到wall.splice(index, 1);
  • wall.get(index); 到墙壁[索引]
  • walls.size()到walls.length
更改数组的声明var randWall = {width, randY, wallWidth, randHeight, 0}; 到var randWall = [width, randY, wallWidth, randHeight, 0];
删除所有公共关键字。
将所有color(0)声明移到函数setup()中, 因为在调用setup()之前不会定义color()。
更改大小(500, 500); 创建canvas(500, 500);
将函数gameScreen(){重命名为其他函数, 例如gamePlayScreen(){, 因为我们已经有一个名为gameScreen的全局变量。当我们使用Processing时, 一个是函数, 另一个是int变量。但是JavaScript会混淆这些类型, 因为它们没有类型。
Score()也一样。我将其重命名为addScore()。
可以在此处找到涵盖此Processing教程中所有内容的完整JavaScript代码。
Processing游戏代码:你也可以做 在此Processing教程中, 我试图解释如何构建一个非常简单的游戏。但是, 我们在本文中所做的只是冰山一角。使用Processing编程语言, 几乎可以实现任何目的。我认为, 这是编程你所想象的最佳工具。我使用此Processing教程的真正目的不是要讲授Processing和开发游戏, 以证明编程并不难。打造自己的游戏不仅仅是梦想。我想向你展示, 只要稍加努力和热情, 你就可以做到。我真的希望这两篇文章能激励大家尝试编程。

    推荐阅读