简体   繁体   English

Three.js-每x秒生成一个对象并向前移动每个对象(沿着Z)

[英]Three.js - Spawn an object every x seconds and move each object forward (along Z)

I am making an endless runner style game using Three.js. 我正在使用Three.js制作无尽的亚军风格游戏。 The basic set up of the scene and idea for the game is a long moving road with cars coming towards you that you have to dodge out of the way of. 游戏场景和构想的基本设置是一条漫长的道路,汽车驶向您,您必须避开它们。 I am still at the early stages of creating this game, and so my first problem is that I need the hero character (who is dodging the cars) to seem like he is moving forwards, and at the same time have the cars seem like they are moving (faster) towards the hero character. 我仍处于制作此游戏的初期阶段,所以我的第一个问题是我需要英雄角色(躲避汽车的英雄)看起来像他在前进,同时使汽车看起来像他们正在(更快)向英雄角色发展。

My thinking was to create road strip objects (the white lines in the middle of a road), and have them move towards the hero character, who is at (0, 0), at a certain speed. 我的想法是创建路标对象(路中间的白线),并使其以一定的速度移向处于(0,0)的英雄角色。

I have successfully created a road strip object and positioned it at the very back of the road ( RoadStrip.mesh.position.z = -5000; ). 我已经成功创建了一个路带对象,并将其放置在路的最后面( RoadStrip.mesh.position.z = -5000; )。 Here is my code for that: 这是我的代码:

var objectRoadStrip = function() {
    this.mesh = new THREE.Object3D();
    this.mesh.name = "roadStrip";

    geomRoadStrip = new THREE.BoxGeometry(20, 11, 300);
    matRoadStrip = new THREE.MeshPhongMaterial({color: Colors.white});

    RoadStrip = new THREE.Mesh(geomRoadStrip, matRoadStrip);
    RoadStrip.name = 'roadStripName';
    this.mesh.add(RoadStrip);
}

function createRoadStrip() {

    new objectRoadStrip();
    RoadStrip.position.y = -72.5;
    RoadStrip.position.z = -5000;

    scene.add(RoadStrip);

}

In the render() function, which is the function that loops over every frame and is called last to make sure the camera and scene update every frame, I am able to successfully move this strip forwards along the z axis by 10 every time render() is called. render()函数中,该函数循环遍历每帧,并在最后一次调用以确保相机和场景更新每帧时,每次render() ,我都能成功地将该条带沿z轴向前移动10 render()称为。 I also added some code so that when the RoadStrip touches (0,0), it is removed from the scene. 我还添加了一些代码,以便当RoadStrip触摸(0,0)时将其从场景中删除。 See this below: 请参阅以下内容:

function render(){

    // moves RoadStrip towards (0,0). When it reaches z = -150, remove that strip from the scene

    if (RoadStrip.position.z <= -150) {
        RoadStrip.position.z += 10;
    } else {
        scene.remove(RoadStrip);
    }

    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

I have also added the following code to the init() function which creates a RoadStrip when the scene is created, and the continues to create a RoadStrip every 10 seconds (roughly every time the RoadStrip reaches (0,0). 我还向init()函数中添加了以下代码,该函数在创建场景时创建RoadStrip ,并继续每10秒创建一次RoadStrip (大约每当RoadStrip达到(0,0)时)。

createRoadStrip();
setInterval( function() {
    createRoadStrip();
}, 10000);

This is similar to the effect I'm going for, but read The Problem section below where I explain what I truly need. 这与我要达到的效果类似,但是请阅读下面的“问题”部分,在其中解释我的真正需求。

The Problem 问题

I need to spawn a RoadStrip every x amount of seconds (still to be decided once I get it working, but lets say 3 seconds for now) continuously. 我需要每隔x秒钟产生一个RoadStrip (这仍然待我确定,但是现在可以说3秒钟)。 Each RoadStrip needs to move towards (0,0) with z += 10 independently. 每个RoadStrip需要独立移动到(0,0), z += 10 When a RoadStrip instance reaches (0,0), it should be removed from the scene, but other RoadStrips should continue to spawn regardless every 3 seconds at the original position ( z = -5000 ). RoadStrip实例达到(0,0)时,应将其从场景中移除,但是无论其他RoadStrips在原始位置每3秒( z = -5000 ),都应继续生成。

My Attempts / Solution Ideas 我的尝试/解决方案构想

I've done a lot of reading on this, trawling through code from other people's endless runner games and reading through SO answers but nothing seems to have worked. 我已经做了大量的阅读工作,从其他人无休止的亚军游戏中寻找代码,并阅读了SO答案,但似乎没有任何效果。 Below are some of the things I have tried, or some things that I feel would work but I am not doing right/don't have a good understanding of: 以下是我尝试过的一些方法,或者一些我认为可行的方法,但我做得不好/对以下内容没有很好的理解:

  1. Idea: Instead of calling the createRoadStrip() function inside a setInterval , push a RoadStrip object to an array every 3 seconds, and then call that array and move the array along the z axis by += 10 . 想法:不用在setInterval内调用createRoadStrip()函数, RoadStrip每3秒将RoadStrip对象推到数组中,然后调用该数组并沿z轴将数组移动+= 10
  2. Possible solution help: I tried changing the setInterval to less than 2 seconds instead of 10 seconds. 可能的解决方案帮助:我尝试将setInterval更改为少于2秒而不是10秒。 This caused the RoadStrip to move along the Z axis for 2 seconds as expected, but of course, after 2 seconds another RoadStrip was spawned, and so the first RoadStrip stopped moving along the Z axis, and the new one did instead (for 2 seconds as well) and this process repeated infinitely. 这导致RoadStrip沿Z轴按预期方式移动了2秒钟,但是,当然,在2秒RoadStrip成了另一个RoadStrip ,因此第一个RoadStrip停止沿Z轴移动,而新的RoadStrip停止了移动(持续2秒钟)。以及此过程无限重复。 This is so close to what I need, but I need each RoadStrip to continue moving, and be remove from the scene when it reaches (0,0) 这非常接近我的需求,但是我需要每个RoadStrip继续移动,并在到达(0,0)时将其从场景中移出

Thanks for taking the time to read my Question, I look forward to your solutions! 感谢您抽出宝贵的时间阅读我的问题,期待您的解决方案!

Examples of similar style games: First , Second . 类似风格游戏的示例: 第一第二

Thanks to @prisoner849 and his link to this thread, I managed to find the solution to the problem, and so I am writing an answer here for anyone who comes across this with the same problem in the future! 感谢@ prisoner849及其到线程的链接,我设法找到了解决问题的方法,因此,我在这里为将来遇到相同问题的任何人写一个答案!

I read through the thread and found a link to this JSFiddle , that includes a successful animation similar to the one I was trying to achieve, and I would highly suggest studying the code of that JSFiddle to fully understand how to create an endless runner effect. 我通读了该线程,并找到了该JSFiddle的链接,其中包括一个与我尝试实现的动画相似的成功动画,并且我强烈建议研究该JSFiddle的代码以完全理解如何创建无穷的跑步者效果。

Here is a detailed explanation of how to do this: 这是有关如何执行此操作的详细说明:

Instead of infinitely creating objects and have them animate forwards until they reach the end point and disappear (like I originally thought was the right solution), you have to create an array of objects and animate that instead. 不必无限创建对象并使它们向前动画直到到达终点然后消失(就像我最初认为的正确解决方案一样),您必须创建对象数组并对其进行动画处理。

Here is my code for doing this: 这是我执行此操作的代码:

var roadStripArray = []

function objectRoadStrip() {

    for (var i = 0; i < 100; i++) {
        geomRoadStrip = new THREE.BoxGeometry(20, 11, 500);
        matRoadStrip = new THREE.MeshPhongMaterial({color: Colors.white});

        RoadStrip = new THREE.Mesh(geomRoadStrip, matRoadStrip);

        RoadStrip.position.set(0, -72.5, -150 - i * 1250);
        RoadStrip.receiveShadow = true;

        scene.add(RoadStrip);
        roadStripArray.push(RoadStrip);
    }

}

The for loop has the code i < 100 as my road is quite long and therefore needs a lot of strips for循环的代码i < 100因为我的路很长,因此需要很多条带

This code: 这段代码:

RoadStrip.position.set(0, -72.5, 0 - i * 1250);

sets the position of each strip to be different from each other, and the number 1250 is the distance between each strip 将每个条带的位置设置为彼此不同,数字1250是每个条带之间的距离

After creating the objects, you must animate them in the render() function. 创建对象之后,必须在render()函数中为它们设置动画。 You have to set them to move along the Z axis, and then create an if statement that says "if any strip reaches the end point (where you want it to disappear), reset it's position back to the start (ie the start of the road for me). This means you are constantly looping through your array of objects, and therefore don't infinitely create them. 您必须将它们设置为沿Z轴移动,然后创建一条if语句,其中说:“如果任何条带到达终点(您希望其消失的位置),请将其位置重新设置为起点(即这对我来说是一条道路),这意味着您不断循环遍历对象数组,因此不会无限创建它们。

Here is the code that animates the strips: 这是带状动画的代码:

// loop that runs every frame to render scene and camera
var clock = new THREE.Clock();
var time = 0;
var delta = 0;
var direction = new THREE.Vector3(0, 0, 1);
var speed = 2000; // units a second - 2 seconds

function render(){
    requestAnimationFrame(render);

    delta = clock.getDelta();
    time += delta;

    roadStripArray.forEach(function(RoadStrip){
        RoadStrip.position.addScaledVector(direction, speed * delta);
        if (RoadStrip.position.z >= 10000) {
            RoadStrip.position.z = -10000;
        } else {
        }
    });
    renderer.render(scene, camera);
}

The code that moves each strip is: 移动每个小条的代码是:

RoadStrip.position.addScaledVector(direction, speed * delta);

You can read more about .addScaledVector here , but essentially this is the code that animates the strip. 您可以在此处阅读更多有关.addScaledVector的信息 ,但本质上,这是使该带动画化的代码。

The if statement then checks if the strip touches 10000 (ie the end of the road), and if it does, sets the position of that strip to -10000 . 然后, if语句检查地带是否触及10000 (即路的尽头),如果触及,则将地带的位置设置为-10000 That strip then moves back towards the end point along the Z axis. 然后,该条带将沿着Z轴移向终点。

We wrap this all in a forEach function to loop through each RoadStrip in the array and animate them all in the same way. 我们将所有这些包装在forEach函数中,以遍历数组中的每个RoadStrip并以相同的方式对其进行动画处理。 We need to animate them individually so that we can detect when one of them reaches the end of the road. 我们需要分别对它们进行动画处理,以便我们可以检测其中之一何时到达路的尽头。

Thanks, hope this helps! 谢谢,希望对您有所帮助!

Usually this kind of scenario is best handled with some kind of particle-system like approach: you don't insert/remove objects continuously to the scene but create a set of objects during initialization, let's say the player can only see 10 road stripes at a time, and your game logic is always moving those 10 stripes, updating positions as needed, once one strip goes out of the field of view, it is recycled at the begining and so on. 通常,这种情况最好用某种类似于粒子系统的方法来处理:您不会在场景中连续插入/删除对象,而是在初始化过程中创建了一组对象,比如说玩家只能看到10条道路条纹。一次,您的游戏逻辑总是移动这10条条纹,并根据需要更新位置,一旦一条条纹超出视野,则在开始时将其回收,依此类推。 I don't think you will find a canned solution that does exactly what you are looking for, you would need to come up with the update logic that suits best your game. 我认为您不会找到能够完全满足您需求的固定解决方案,您需要提出最适合您游戏的更新逻辑。

I have an example of custom particle system there . 我有自定义的粒子系统的例子存在 Once a particle is getting out of scope, it is made available for the system when it needs to emit a new particle. 一旦粒子超出范围,当它需要发射新粒子时,该粒子便可供系统使用。 The number of particle in the pool is always constant and can be defined by the user here just for testing purpose. 池中的粒子数始终是恒定的,用户可以在此处定义其目的仅仅是为了进行测试。 A similar approach can be used to manipulate your infinite stripes. 可以使用类似的方法来操纵您的无限条纹。 The repo for that code is available at https://github.com/leefsmp/Particle-System but you can find many other particle system implementations out there, this one is a bit specific to my needs. 该代码的存储库位于https://github.com/leefsmp/Particle-System,但是您可以在那里找到许多其他粒子系统实现,这是我的特定需求。

Hope that helps. 希望能有所帮助。

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM