Code Monkey home page Code Monkey logo

Comments (21)

fenomas avatar fenomas commented on May 18, 2024

Hey, sorry, I really need to document this stuff.

Babylon.js has a lot of game-engine features that this library doesn't use, and collision checking is one of them. Setting mesh.checkCollisions tells Babylon to do something about mesh-vs-mesh checking (I haven't looked at the details), but it's completely orthogonal to this engine, voxels, and so on.

Here's the high-level view of what this engine supports related to what you're looking at:

  • Any entity with the physics component will collide with solid terrain blocks (that is, block IDs that were registered with solid set to true
  • Any entity with the collidesTerrain component will emit an event (to the component callback) when it collides with voxel terrain (i.e. solid blocks)
  • Entities with the collidesEntities component will emit an event when they collide (i.e. overlap) with each other. But there's no physics for this - they just emit events.
  • Custom meshes only exist for rendering purposes. The physics and collision tracking systems only know about voxels and entities.

So, if you assign a custom mesh to a particular voxel ID, noa will make an instance of that mesh every time the block shows up, but the physics engine only knows about the voxel and its solidity. If you want a non-solid voxel that does something when the player overlaps it, what I do is have a voxel that creates an entity in its onSet / onLoad handlers, and that entity does something on collisions with the player entity. But in that case the voxel won't collide (in the physics sense).

So, a little limited, but that's how things stand as of now. Let me know if that's clear!

from noa.

fenomas avatar fenomas commented on May 18, 2024

Incidentally now that I type all that, the collidesTerrain component doesn't really make sense. I should remove it and make onCollide events happen equivalently for any entity with the physics component.

from noa.

fenomas avatar fenomas commented on May 18, 2024

Follow-up: I now remember why collidesTerrain is a separate component - because I had a to-do item someday to make it possible to have physics-driven entities that don't collide with terrain (ghosts, etc). Not sure that's worth spending time on, but anyway.

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

So, you mean I should be registering the custom mesh as a solid block even though it is not necessarily a block? That might work if I want to add some items but I am not sure for other things.

I am asking because I want to import some mobs and I want them to have collisions and I don't want to handle them as other blocks.

from noa.

fenomas avatar fenomas commented on May 18, 2024

Right now the physics in this library only knows how to collide entity AABBs and solid voxels. It has no idea whether the entities or voxels have meshes associated with them or not.

If you want voxels that are partly-solid - where the collision volume is still an AABB, just not the full voxel, you could try hacking voxel-physics-engine to support that. It wouldn't be super trivial, but certainly possible. (It's on my to-do list, just not very high 😁)

But if you want something that resembles "real physics" - where objects aren't just AABBs, and entities collide with each other - then that probably isn't feasible with the current physics engine. It's relatively easy to replace the default physics engine with a real one (like cannon.js), but this would only make sense if the engine supported voxel terrain as a collision object type. I've played with extending cannon.js to do that -
see here - but haven't gone far enough to see if it's really doable.

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

Oh I see. I took a look at the projectile code you had, since it seemed to be a nice and simple way to add collision between entities. Here is my current code:

    this.blankmesh = this.make_test_mesh();
    this.blankmesh.position = new BABYLON.Vector3(x, y, z);

    let blank_mat = new BABYLON.StandardMaterial('blank-mat', this.scene);

    // Id 254, so it won't bother any of the other blocks
    this.noa.registry.registerBlock(254, {
        blockMesh: this.blankmesh,
        opaque: true,
        solid: true,
    });

    // Make an instance
    let new_sprite_mesh = this.noa.rendering.makeMeshInstance(this.blankmesh, false);

    let vectorsWorld = this.blankmesh.getBoundingInfo().boundingBox.vectorsWorld; 
    let width = Number(vectorsWorld[1].x-(vectorsWorld[0].x));
    let height = Number(vectorsWorld[1].y-(vectorsWorld[0].y));

    // usage: entities.add( pos, w, h, mesh, meshOffset, doPhysics, shadow
    var eid = this.noa.entities.add(new BABYLON.Vector3(x, y, z), width, height, new_sprite_mesh, [0,0,0], true, true);
    
    // make it collide with player
    this.noa.entities.addComponent(eid, this.noa.entities.names.player);

But the problem now is that it doesn't seem to show anywhere, can you spot any problem?

EDIT: I looked into makeMeshInstance and it seems that it handles already whether it should be added as a DynamicMesh or not, so that shouldn't be the problem, right?

from noa.

fenomas avatar fenomas commented on May 18, 2024

Hi! This is just a guess, but I think that the problem is probably that you've passed a Babylon Vector3 into a method that expects regular [x, y, z] array (for the position argument of entites.add).

As a general rule, noa uses arrays (technically Float32 arrays) for vectors, because I do all my vector twiddling with the gl-vec3 library. Babylon uses its own vector objects (that look like {x:x, y:y, z:z}), but in general noa doesn't use them except internally. I'm pretty sure there are a few exceptions to that - I haven't been completely rigorous about it. But in general, most noa APIs that take a vector are expecting an array.

So, since the code above passes in a Babylon vector, I'm guessing the entity adder probably winds up setting the mesh's position to [NaN, NaN, NaN] and that's why it's not appearing.

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

Yeah, that was it!

Now it appears but the shadow is quite off and the mesh doesn't collide with the player.

Should I have used this.noa.entities.names.player or something like this.noa.entities.names.collideEntities (similar to collideTerrain)?

from noa.

fenomas avatar fenomas commented on May 18, 2024

Okay, looking back a few posts I think there are a few issues confounding each other that I need to explain.

Fundamentally, noa understands two kinds of things - blocks (i.e. voxels) and entities. When you register a block type with a custom mesh, that's meant for things that are part of the voxel terrain, but you don't want them to get meshed like a voxel. So - a flower, a mailbox, etc. Then, when noa is building a "chunk" of terrain, and it encounters a block ID with a custom mesh, instead of making that block part of the terrain, now will create an instance of the custom mesh and put it at the given voxel.

But defining a block ID with a custom mesh doesn't do anything to the world unless you also set some voxels with that ID.

Entities, meanwhile, are completely separate - they represent anything that can move around, etc. The only thing noa really does with entities is, if they have the physics component, it will handle their velocity and whatnot, and keep them from moving through solid voxels.

In general, it's probably necessary to look inside components you want to use, to get some idea what they do. E.g. the player component has no functionality at all, it just tags which entity is the player. (Also, I think it's not currently used - I think I need to remove it!)

Anyway, if I understand your question correctly then the collideEntities component may be what you need. Note, when I said earlier that the physics system doesn't collide entities, I meant it doesn't make the bounce off each other, etc. The collideEntities component does detect entity collisions, and send an event, which is likely what you need for projectiles, etc.

from noa.

fenomas avatar fenomas commented on May 18, 2024

Oh, and for your current bug, you might try not using the entities.add() helper, and instead try adding the various components (position, shadow, physics) one-by-one. This might show where the issue is. Note that some components depend on each other (e.g. the physics component assumes its entity has a position.)

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

Ok, just to clarify my goal: I want to create a second player (some sort of NPC or mob with AI) which just needs to be able to acts like any other solid object. If it can have some physics concerning gravity and whatnot: awesome, but I would like to start off by not being able to go through it with my player.

What would be the simplest thing to do?

Imagine having a mesh which acts like your mobs in the testbed demo but which cannot be walked through.

from noa.

fenomas avatar fenomas commented on May 18, 2024

Okay, if I understand you correctly then it's back to my first answer - this engine only models terrain and entities, where terrain is solid but doesn't move, and entities can move but are not solid. The collideEntities component will report entities that are overlapping, and you could catch that event and apply a force or impulse to push one entity away from the other, but the engine can't currently model having entities physically collide with each other the way they do with terrain.

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

Oh I see!

How do I catch that event? Something like noa.on('onCollision', function(eventData) { ... }); ?

from noa.

fenomas avatar fenomas commented on May 18, 2024

Every component works the same way - you add a component to an entity, and set any parameters in the state object for that entity-component pair. In this case it would look like:

var id = // my entity ID
var state = {
    callback: function(other) console.log('Entity', id, 'collided with', other)
}
noa.entities.addComponent( id, noa.entities.names.collideEntities, state )

Or something like that!

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

That worked nicely, I will try to move the player to its previous position anytime there is a collision, let's see :D

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

Hey @andyhall,

as an extension of this question: I am currently having a hard time properly offsetting my custom mesh.

Here is my code:

this.new_sprite_mesh = this.noa.rendering.makeMeshInstance(this.blankmesh, false);

        // Flip X axis
        this.new_sprite_mesh.scaling.x = -scale;
        this.new_sprite_mesh.scaling.y = scale;
        this.new_sprite_mesh.scaling.z = scale;

        let width = Math.abs(this.new_sprite_mesh.getBoundingInfo().boundingBox.extendSize.x * this.new_sprite_mesh.scaling.x);
        let height = Math.abs(this.new_sprite_mesh.getBoundingInfo().boundingBox.extendSize.y * this.new_sprite_mesh.scaling.y);

        // usage: entities.add( pos, w, h, mesh, meshOffset, doPhysics, shadow
        let eid = this.noa.entities.add([position.x, position.y, position.z], width, height , this.new_sprite_mesh, false, true, false);
        
        this.noa.entities.addComponent(eid, this.noa.entities.names.shadow, { size: width * 2});

        let state = {
            callback: function(other) {
                if(other === this.noa.playerEntity) {
                    this.move_player_to(this.previous_player_position);   
                }
            }.bind(this),    
        };

        // // make it collide with player
        this.noa.entities.addComponent(eid, this.noa.entities.names.collideEntities, state);

The mesh is correctly shown but the problem is the offset (relative to the shadow and its collision). I tried every sort of combination that I could think of but still nothing.

I checked in the debug layer and the bounding box of my meshes is tightly fitting around their geometry, so that's not the problem.

I simply want to have the lowest part of the bounding box of my mesh touching the floor and centered within their shadow. How can I do that?

from noa.

fenomas avatar fenomas commented on May 18, 2024

Hey, sorry for the late reply. From reading the code above, I think the answer here is to change the mesh offset vector, but let me just try to explain what assumptions the library is making.

Effectively, an entity with a mesh has two positions. There's the "noa position", which is an [x, y, z] array and is stored in the entity's position component. This position is what noa uses to handle the physics, and entity collisions, etc. This noa position refers to the feet position of the entity - i.e. the bottom-center of its bounding box.

On the other hand there's the "Babylon position", that Babylon knows about, and uses to render meshes. Note that babylon positions have arbitrary centering - the babylon position could be the mesh's center, or one of its corners, or whatever, depending on how the mesh was made.

So with all that said, all noa does each frame is, it calculates an entity's "noa position" (from physics etc), then it overwrites the entities "Babylon position" to be equal to the noa position plus the mesh offset.

So, if physics and collisions are working right but the mesh is rendering in the wrong spot, the probelm should be with the mesh offset property of the mesh component. If that's not working, then I suspect something else might be going on (like some property getting set to NaN or whatever), but that's just guessing.

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

Ohhh, I see! But shouldn't the mesh have just an incorrect Y position? My meshes seems to be completely off on all axis.

from noa.

fenomas avatar fenomas commented on May 18, 2024

Well, if I understand your issue correctly then my best guess would be that the problem is with the Babylon mesh's registration point, which in principle can be anywhere. When you make meshes with its built in methods (Babylon.Mesh.CreateBox or whatever) I think the registration points are always in the center, but if the mesh was imported from somewhere then there's no way of knowing.

But I could just be misunderstanding what's going on.

from noa.

Nesh108 avatar Nesh108 commented on May 18, 2024

Yeah, I think that's it. Do you know of any way to reset those points to the center?

I am using this: https://github.com/Nesh108/babylon-voxel-critter , to import a mesh from the VoxelBuilder. Is there anything you can see that might misbehave when added to your engine?

from noa.

fenomas avatar fenomas commented on May 18, 2024

Well, the key should be changing the [0,0,0] offset when you add the entity, but the correct values depend totally on how the mesh was made.

That is, a mesh's "center" is baked into its vertex data, right? Like, if a mesh has vertices whose x coordinates are all between -1 and 1, then that mesh is more or less centered on the x axis. But if you went through and added 5 to every x vertex, you'd have the exact same mesh, but centered around x=5, so then you'd want a mesh offset of [-5,0,0] when adding it to an entity.

But the vertex values in your mesh are down to whatever tool created them. Probably the tool has some idea of where the "origin" is, and it generates vertex data that are relative to that origin.

I expect you could investigate this by importing the mesh into the scene, and then looking at mesh.getBoundingInfo().boundingBox - e.g. the maximum and minimum properties, which I think should be the extents of the mesh's data in local coordinates.

Hope this helps!

from noa.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.