I’ve been able to create certain game mechanics for individual meshes, but I’m not sure how to apply these to the clones (grey boxes) and instances (yellow boxes).
Each grey box starts with 100 health, and loses it steadily over time (example 10 seconds).
When a grey box and a yellow box collide, that grey box’s health resets to 100, and the yellow food box disappears.
If a grey box does not collide with a yellow box within 10 seconds, the grey box disappears.
Again, I’m not having trouble creating these mechanics for individual meshes (i.e. “box” and “food”), but rather for all the other clones and instances (i.e. “box24” and “food116”).
Any help or suggestions would be greatly appreciated
I have no idea what mesh.metadata is, but it sounds like a great solution! Hopefully I can find documentation or examples of how to implement this.
However, even if I can get each instance or clone to store metadata, I still can’t figure out how to get hundreds of different meshes all with unique names to recognize each other (i.e. an intersection).
For instance, in the code below, when I reference ALL of the 200 food instances from the foodArray (foodArray[i]), the scene crashes However, this code works if I check for an intersection with just a single instance (replace foodArray[i] with just “food”).
scene.registerBeforeRender(function () {
for (var i = 0; i < 200; i++) {
if (cloneArray[i].intersectsMesh(foodArray[i], false)) {
cloneArray[i].material.diffuseColor = new BABYLON.Color3(1, 0, 0);
}else{
cloneArray[i].material.diffuseColor = new BABYLON.Color3(0, 1, 0);
}
}
});
I’m still unable to solve this problem unfortunately, so I’m going to try and simplify the question below for anyone who might know the solution.
How can two objects from different arrays detect an intersection when their specific ID is not known by the user? Example: “box12” and “food143” (named when created: (“box” + index), and (“food” + index)).
Without a playground I cannot work out why it crashes but with the code you show
registerBeforeRender(function () {
Copy to clipboard
for (var i = 0; i < 200; i++) {
if (cloneArray[i].intersectsMesh(foodArray[i], false)) {
cloneArray[i].material.diffuseColor = new BABYLON.Color3(1, 0, 0);
}else{
cloneArray[i].material.diffuseColor = new BABYLON.Color3(0, 1, 0);
}
}
});
each cloneArray will only be checked against the one entry in the foodArray, the one with the same index. For any in the cloneArray to be checked against any in the foodArray you need two loops with i and j and check
I was actually able to get things working with the code below. I will definitely investigate the SPS, as it might be a better option for my project in the long run. Does the SPS offer any advantages over using instances? I’ve only been programming for a month, so I’m not sure if what I wrote below is the best solution, but it works!
for (var i = 0; i < cloneArray.length; i++) {
cloneArray[i].actionManager = new BABYLON.ActionManager(scene);
foodArray.forEach((food) => {
cloneArray[i].actionManager.registerAction(
new BABYLON.ExecuteCodeAction(
{
trigger:BABYLON.ActionManager.OnIntersectionEnterTrigger,
parameter:food
},
function(){
food.dispose();
}
)
);
});
}
I just realized that there actually is one element of the code above that is not 100%. I’m unable to get both the “food” and the cloneArray[i] mesh to disappear.
lines 73, 74 could just have been cloneB.lifeTimeRemaining = 60 * 1000; I believe the advantage of using metadata is that Babylon.js picks the metadata property up when the mesh is exported and serializes it.
Thanks for the updates to the code! Someone else also mentioned that metadata would be useful for this project, but I couldn’t at the time find any examples, so it’s really helpful that you added it. When I researched it, it seemed like metadata was something that got imported along with a mesh, or was contained in a separate file. It seems like metadata will help me accomplish the most important part of this project, which is to have randomly-generated creatures with various traits that can change over time.
When the creatures (grey boxes for now) move around, they will continuously lose energy. It looks like you set this up with lifeTimeRemaining (60 seconds). This is perfect because I had no idea how to accomplish this. Now, I’ll see if I can reset that 60-second clock for each individual creature when it intersects with a food item.
The most challenging part of this project (I think ), will be the digital DNA element involving the inheritance of metadata. I don’t even know if this will be possible, but I hope so!
For instance:
Creature 1: metadata trait A = 1, metadata trait B = 2
Creature 2: metadata trait A = 3, metadata trait B = 4
When they intersect (reproduce) “offspring” with random trait values:
Offspring creature: metadata trait A = (1 or 3), metadata trait B = (2 or 4)
Thank you again @JohnK for the help and suggestions!
This should be straightforward to do on intersection.
It could be interesting to vary the life time for each predator and for each food item to be of varying size and add an amount of life when eaten proportional to its size.
I randomized their speed and made that inversely proportional to their lifespan.
There are two issues now:
I can only use one action manager for the clones. One removes the food, the other scales the y axis, but only one at a time works (whichever is read last by the scene).
I have absolutely no idea how to combine metadata randomly when two clones intersect to create a new clone “offspring.”
The dance two box clones make on meeting is completely accidental but I think adds something.
From my personal point of view the use of actionManager in this particular situation with multiple loops on the same array is a bit messy so I have still avoided them. Obviously you may prefer them, its up to you.
I am thinking about offspring and have the seed of an idea. Hope you don’t mind the continuing interruptions.
These are just wild thoughts on model genetics that I am making up as I go along, so please bear that in mind.
Currently too related traits are used speed and life/energy which directly relate, ie faster speed less life. Obviously this is a bit too simple. Lets make it a little more complicated. (Hopefully I will not get too carried away.
First of all I added whole life and whole life decay so that when the predator eats it can never completely get back to full life time so must die eventually.
consider these as traits
P Energy Potential - the maximum energy storeable
D Energy Decay - fractional decrease of energy potential over time
T Decay Time - the rate of decay of energy over time
B Energy Burn - the fractional amount of energy used just by moving
S Speed Potential - maximum speed
Mass - scale of size constant over time
With these you could work out current speed and current energy (somehow or other but I want to concentrate on made up genetics)
Consider two type of entities A and B with traits inherited from either A or B type
So new traits A and B and offspring only produced when A and B meet
Type P D T B S M
From A B A A B B
. . . . . 1 0 1 1 0 0 using binary for A and B
for variation use 80% from A and 20% from B for a 1 or vice versa for a 0
Further vary this by having weak types a and b
So intersections that produce offsprings can be AB, aB, Ab, ab
Glad to see you’re still following this project I definitely need and appreciate the help!
I’m a biology teacher, and I got into programming about a month ago to make educational games and simulations. Eventually, these digital creatures will have a full array of traits that follow the actual rules of genetic inheritance. They’ll have realistic metabolisms, movements, and behaviors as well (I hope!). I’ll want this project to be a fun educational simulation that students can use to study genetics, ecology, and evolution. I’m finding out that this was a very ambitious first project from a new programmer perspective!
So, with that backstory, you’re ideas are excellent and definitely in line with what I’m trying to accomplish.
You suggested programming variation in trait inheritance probabilities and including “weak” types. Both ideas are great, and would simulate how actual genes (alleles) are passed from parent to offspring, and how some genes are recessive to others.
So, back to the programming questions!
You added some new code that I don’t yet fully understand and will have to study. I don’t want to ask too many questions, so I suppose I’ll ask about using different variable letters for the various arrays (i, k, and j). My guess is that the different letters allow the program to store different states of the same mesh (i.e. box1 from the “i” array, and box1, from the “j” array…)?
Also, for the inheritance component, any suggestions for combining metadata from two meshes when they intersect?
For instance, similar to what you referenced in your last post, let’s say:
box1 has a maxSpeed of 0.4
box37 has a maxSpeed of 0.2
When they intersect, they create a NEW clone with a maxSpeed of 0.3 (average from the two parents).
let variable (letter) in a for…loop can tell you how far you are through an array
for (let i = 0; i < A.length; i++) {
//do something with A[i]
}
for (let i = 0; i < B.length; i++) {
//do something with B[i]
}
The above code works because there is no overlap between the uses of i.
Suppose we want to make a list “a1”, “a2”, “a3”, “b1”, “b2”, “b3”, “c1”, “c2”, “c3” we can do that with an inner and outer loop
for ( let i = 0; i < B.length; i++) {
for (let j = 0; j< A.length, j++) {
// combine B[i] with A[j]
}
}
If you try
for ( let i = 0; i < B.length; i++) {
for (let i = 0; i< A.length, i++) {
// combine B[i] with A[i]
}
}
Things mess up because the outer and inner loop overlap the use of i. The inner loop increments i past its limit in the outer loop.
As you have know you can get away without using i, j etc by using forEach
but again you cannot just use item for both loops.
There are advantages to doing it this way but for combining ‘like with like’ using indices allows you to miss out combinations already undertaken (unless order matters eg a[i] - a[j] is not the same as a[j] - a[i] )
for ( let i = 0; i < A.length; i++) {
for (let j = i + 1; j< A.length, j++) {
// add A[i] + A[j] is only done once
}
}