使用p5.js从一个场景过渡到下一个场景



我目前正在使用p5.js创建一个交互式故事。我的主要问题是,我似乎不知道如何编写从第二个场景过渡到第三个场景的逻辑。

我在这里使用了p5.js的切换场景示例作为参考指南。我还没有真正掌握mousePressed()函数背后的逻辑,以便将其用于我的优势。

function mousePressed() {
if (scene1 == true) {
if (mouseX < width / 2) {
//do something
scene2 = true;
} else if (mouseX > width / 2) {
//do something else
scene3 = true;
}
// turn scene 1 off
scene1 = false;
} 
}

该函数将画布划分为两个位置,以便mousePressed()函数执行并转换到另一个场景。

我只想按画布上的任何位置作为从第一个场景过渡到第二个场景的起点,但后来我想按特定对象,以便从第二个到第三个场景过渡。

当前代码段:

function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
easycam = new Dw.EasyCam(this._renderer, {
distance: lunarDistance * 1.3
});
}
function draw() {
if (scene1 == true) {
drawScene1();
} else if (scene2 == true) {
drawScene2();
} else if(scene3 == true){
drawScene3();
}
}
function drawScene1() {
...
}
function drawScene2() {
...
}
function drawScene3() {
...
}
function mousePressed() {
if (scene1 == true) {
if (mouseX == width) {
scene2 = true;
if (mouseX == width) {
scene3 = true;
}
}
scene1 = false;
} 
}

不幸的是,这似乎不起作用。我试着通过删除mousePressed():来进一步修改它

function draw(){
if (scene1 == true) {
drawScene1();
if(mouseIsPressed){
scene1 = false;
scene2 = true;
drawScene2();
}
} 
}

这似乎是可行的,但它禁用了我的动画,并完全把它搞砸了。

我该怎么办?

draw()内部使用if来确定渲染哪个场景的方法对于小草图来说可能很好,但不是特别可扩展的,包括布尔值、难以推理的条件、共享状态和/或程序必须了解魔术/硬编码的变量名。

每当你发现自己在处理thing1thing2thing3…时。。。,thingN,前进的路径几乎总是一个对象或一个数组。对于长的if-elseswitch链,常见的重构是使用函数的数组或对象。

场景本质上是状态机,是可设置关键帧/可索引对象或函数数组的完美用例。如果您以逐步的方式处理场景,数组可能是最好的,因为它们是有序的,并且可以使用索引或shift()按顺序逐步处理。请参阅此答案以了解解决此问题的方法。

如果你的场景不是那么线性,那么给它们起名字而不是数字可能是更好的浏览方式。这里有一个例子:

const scenes = {
loading: () => {
let ticks = 0;
frameRate(3);
mousePressed = () => {};
draw = () => {
clear();
text(`loading sceen, please wait${".".repeat(ticks % 4)}`, 50, 50);
if (++ticks > 10) {
frameRate(60);
scenes.menu();
}
};
},
menu: () => {
mousePressed = () => {
scenes.gamePlay();
};
draw = () => {
clear();
text("menu scene. click to play", 50, 50);
};
},

gamePlay: () => {
mousePressed = () => {
fill(0);
scenes.gameOver();
};
let x = 0;
fill(50, 50, 160);
draw = () => {
clear();
text("gameplay scene. click to go to game over", cos(x) * 20 + 50, 50);
x += 0.1;
};
},

gameOver: () => {
mousePressed = () => {
scenes.menu();
};
draw = () => {
clear();
text("game over scene. click to go to menu", 50, 50);
};
},
// ... more scenes ...
};
function setup() {
createCanvas(500, 100);
textSize(20);
}
function draw() {
scenes.loading();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>

当然,切换场景的条件会更复杂,而且在很多情况下可能不会使用鼠标进行切换(游戏状态或按钮也同样可能),但本例说明了这样一种想法,即每个场景都将以事件驱动的方式用自己的实现替换p5的窗口库函数,避免任何CCD_ 13,并保持代码可读性和模块化。您可以很容易地将场景分解为单独的文件。

";设置";每个场景的逻辑都在顶级scenes.yourScene函数中烘焙,它为状态提供了一个很好的闭包,该状态应该在draw调用之间持续存在,而不会污染其他场景。您可以根据需要将变量移出全局或共享范围,以在场景之间保持数据,例如总得分。

尽管上述示例中的场景之间的关系很简单,但场景可以测试不同的条件以过渡到任何场景,例如单独的输赢场景。触发转换的条件块表示退出状态的清理/拆卸逻辑。对于非常复杂的游戏和动画,嵌套场景以及分别使用数组和对象的组合进行逐步过渡和状态机过渡应该是非常可行的。

绘制一张图表显示应用程序中的场景以及触发转换的条件通常很有用。或者,写下应该采取哪些行动来设置和拆除每个场景:

例如,上述应用程序的场景可以这样可视化:

.---------.
| loading |
`---------`
|
loaded
|
v
.------.          .-----------.
| menu |--click-->| game play |
`------`          `-----------`
^                    |
|                  click
|                    |
click                  v
|              .-----------.
+--------------| game over |
`-----------`

最后,如果覆盖p5知道的draw函数会让你感到困扰,你可以添加一层间接层,在几个不同的选项之间切换一个本地函数,然后从draw以一种比p5:侵入性更小的方式调用它:

const menuScene = () => {
if (someCondition) {
renderScene = gameScene;
}
// update and draw menu stuff
};
const gameScene = () => {
if (someCondition) {
renderScene = menuScene;
}
// update and draw game stuff
};
let renderScene = menuScene;
function draw() {
renderScene();
}

如果没有闭包,我们将丢失特定于场景的设置代码和局部变量,但使用与第一个示例中显示的模式类似的模式重新引入就足够容易了。

同样的策略适用于设置每个场景的鼠标和键盘等处理程序。

另请参阅Trying to use p5 to change states after pressing button,but nothing when click the button for a DOM oriented example。

鼠标按压事件:P5引用

语言参考应该是你应该搜索的第一个地方。这里在p5参考中描述了鼠标按压功能

以下是引用中的事件描述片段。

每次按下鼠标按钮后,都会调用mousePressed()函数一次。mouseButton变量(请参阅相关的引用条目)可用于确定按下了哪个按钮。如果没有定义mousePressed()函数,那么如果定义了touchStarted(),则会调用它


否定

思考如何应用否定来管理事件。

scene1 = !scene1; // This would turn your scene on or off

鼠标按下事件

这里的代码片段会中断,因为它只绘制1帧,并且由于场景1设置为false,所以在第一帧之后无法访问其他条件。

function draw(){
if (scene1 == true) {
drawScene1();
if(mouseIsPressed){
scene1 = false;
scene2 = true;
drawScene2();
}
}}

您要做的是首先检查鼠标点击的位置。根据鼠标单击更改场景。有很多方法可以做到这一点。跟踪布尔值和变量太繁琐,而且容易出错。那么,你该如何避开这个问题呢?有什么收藏品可以帮助你吗?对

您可以使用列表或任何其他风格的集合来帮助轻松跟踪场景。要执行此操作,请使用指针跟踪当前场景,并且仅在指针位于该场景上时绘制该场景。

即:if (pointer==1){drawScene1();}


我相信你可以解决剩下的问题。

最新更新