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

xnifntxz  于 2022-12-25  发布在  Java
关注(0)|答案(2)|浏览(167)

我目前正在使用p5.js来创建一个交互式故事,我的主要问题是我似乎不知道如何编写从第二个场景过渡到第三个场景的逻辑。
我使用了p5.js的切换场景示例here作为参考指南,但我还没有真正掌握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();
        }
    } 
}

这似乎工作,但它禁用我的动画和混乱了它完全。
我该怎么做呢?

jckbn6z7

jckbn6z71#

draw()中使用if s来决定渲染哪个场景的方法可能适合小草图,但可伸缩性不是很好,涉及布尔值、难以推理的条件、共享状态和/或程序必须知道魔术/硬编码变量名。
无论何时你发现自己在处理thing1thing2thing3,...,thingN,向前的路径几乎总是一个对象或数组,对于长的if-elseswitch链,常见的重构是使用函数的数组或对象。
场景本质上是state machines,它是可键控/可索引对象或函数数组的完美用例。如果你以逐步的方式处理你的场景,数组可能是最好的,因为它们是有序的,可以用索引或shift()顺序地逐步处理。参见this answer了解这方面的方法。
如果你的场景不是线性的,给它们命名而不是编号可能是浏览它们的更好方法。

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.5.0/p5.js"></script>

当然,切换场景的条件会更加复杂,而且在许多情况下可能不会使用鼠标进行切换(游戏状态或按钮也是如此),但是这个例子说明了每个场景将以事件驱动的方式用它们自己的实现来替换p5的窗口库函数,避免任何if s并保持代码的可读性和模块化。你可以很容易地将场景分解成单独的文件。
每个场景的"设置"逻辑都包含在顶层scenes.yourScene函数中,该函数为draw调用之间的状态提供了一个很好的闭包,而不会污染其他场景。您可以根据需要将变量移出全局或共享作用域,以在场景之间持久保存数据,如总的最高得分。
尽管上例中场景之间的关系很简单,但场景可以测试不同的条件以转换到任何场景,例如单独的赢/输场景。触发转换的条件块表示退出状态的清理/拆除逻辑。对于非常复杂的游戏和动画,嵌套场景以及使用数组和对象的组合分别用于逐步和状态机转换应该是相当可行的。
绘制一个图表来显示应用中的场景以及触发转换的条件通常很有用。或者,写下设置和删除每个场景时应采取的操作:
例如,上面应用的场景可以这样可视化:

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

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

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

如果没有闭包,我们将丢失特定于场景的设置代码和局部变量,但是使用类似于第一个示例中所示的模式重新引入这些代码和变量是很容易的。
同样的策略也适用于为每个场景设置鼠标和键盘等处理程序。

dbf7pr2w

dbf7pr2w2#

鼠标按下事件: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();}
我相信你可以从这里解决剩下的问题。

相关问题