A Virtual World - JavaScript Course: Lesson 5 / 11 [Procedural Generation with JavaScript]

preview_player
Показать описание
Welcome to the course where we build a self-driving car simulation in a virtual world. In this video we're diving into the art of adding decorative elements to the virtual world—specifically, buildings and trees. In this video we start by defining the bases of these structures.

Now, you might wonder why not use the same graph editing tools we've explored before? Well, if you're planning to create expansive worlds and desire precise alignment, it can get quite tedious. So, we're going to leverage the functionalities we already have and implement a clever algorithm for procedurally generating buildings alongside the roads. And for that extra touch of realism, we'll randomly place trees where they naturally fit.

Admittedly, this solution may limit your ability to design buildings exactly as you envision them, but the trade-off is worth it. With this approach, world generation becomes incredibly fast and straightforward. In fact, you'll be able to build vast cities in no time! 🏢🌳

Here's a sneak peek of the algorithm: We start by creating thicker envelopes, then use the same process as before to extract the outer segments. We keep the segments long enough to support at least one building and, for the exceptionally long ones, divide them into multiple supports. Finally, we generate polygons around these structures using envelopes and apply some fine-tuning to achieve the desired results.

Have Fun! :-)

⭐PLAYLIST⭐

⭐FINAL APP⭐

💻CODE💻
4. Roads = follow along
5. Buildings And Trees= code after this lesson

💻COPY CODE FROM HERE💻

⭐ALL PREREQUISITES⭐

⭐My Video on Distance to Segment⭐

☕Buy me a Coffee?☕

⚡️Join this Channel⚡️

⭐Timestamps⭐
00:00 Introduction
01:17 Top-level code
03:03 Generating Buildings
19:58 Generating Trees
26:55 Avoid illegal locations
39:18 Fine-tuning
Рекомендации по теме
Комментарии
Автор

Radu converting Friday to Friyaayyy🎉🥳. What an absolute delight 😌

serveshchaturvedi
Автор

I've been programming for about 10 years, and have been completely self taught. The journey was difficult. I am only now going to college to get a degree so I can make a career out of it(3 yrs in). I wish I had found a channel like this when I first started programming 10 yrs ago. I started programming using batch and I made a text based game which was really fun but quickly found out how limited the language was and eventually moved to java and started learning encryption, and networking. I ended up making a messenger application and eventually a 3D game engine. I've watched a few of your videos, and your work is incredible, and how you explain everything in detail is amazing. I hope you youtube career goes well. I found you by watching the machine learning series you have which was amazing. ML and AI have recently became my goals for programming and I cannot wait to see where this channel goes. Side note I typically use UE5 these days(c++) as a base because it allow for quick prototyping. I wish I had found your channel in time for that coding challenge you held recently hope to see more eventually.

kevinbittner
Автор

Another awesome episode! It's so interesting to see how everything is generated using 'simple' functions that we've implemented before. This series is really cool! Nice work Radu!

pesterenan
Автор

Whenever I want to refactor, I tell myself, wait, he will do so in the next episode, and you always do :). Amazing job.

EDIT: Instead of using these loops to check if we want to keep or not something based on a condition we could use array.some which makes everything more compact.
For example

```
!occupiedAreas.some((poly) => poly.containsPoint(p)) &&
!trees.some((tree) => Point.getDistance(tree, p) < this.treeSize) &&
trees.push(p);
```
says there is not any occupiedArea that contains the point and there is no tree within a distance, the last && will be executed.

KostasOreopoulos
Автор

I can't thank you enough sir... You make complex things look easy!!.. I've been following you for a while now and it's has been a rich experience to me. Learning new tricks and techniques every time ... Thank you everything you do 💯🤗

abdulkadirusman
Автор

We even learned a little about procedural generation. Neat!

TORMENTUMM
Автор

Amazing channel and best tutorials, thank you bro

joo.online
Автор

After just 'translating' the js code to Python while watching the video, I did some refactoring to make my code more Pythonic. I want to show the result for generating the trees.
It's an example of why I love Python so much.

def _generate_trees(self):
area_borders = self._get_area_borders()
polys_to_avoid = self.buildings + [envelope.polygon for envelope in self.envelopes]
trees = []
for tree in self._valid_trees(trees, area_borders, polys_to_avoid):
trees.append(tree)
return trees

def _valid_trees(self, trees, area_borders, polys_to_avoid):
left, right, top, bottom = area_borders
while True:
for _ in range(100):
tree = Point(
linear_interpolation(left, right, random.random()),
linear_interpolation(top, bottom, random.random())
)
if not self._in_or_near_poly_to_avoid(tree, polys_to_avoid)\
and not self._near_other_tree(tree, trees)\
and self._not_to_far(tree, polys_to_avoid):
yield tree
break
else:
break

def _in_or_near_poly_to_avoid(self, tree, polys_to_avoid):
return any(
polygon.contains_point(tree)
or < self.tree_size / 2
for polygon in polys_to_avoid
)

def _near_other_tree(self, tree, trees):
return any(
distance(tree, other_tree) <= self.tree_size
for other_tree in trees if other_tree != tree
)

def _not_to_far(self, tree, polys_to_avoid):
return any(
< self.tree_size * 2
for polygon in polys_to_avoid
)

gustvanmierlo
Автор

I am not sure if the trees really work according to this logic. I would suggest manipulating the radius which would add a nice touch, but I don't want to deviate since I don't know what is next, so will keep it for now.

backstabba
Автор

now I know what crack addiction feels like. MORE! I WANT MORE!

pizdaxyu
Автор

Hey, Radu, just discovered something kinda funny. In JS, you can draw a filled circle by using a path with the fill() method, but it's actually faster to set lineWidth to 2 * radius and use lineTo() with stroke(). The behavior is probably unpredictable, but seems to work just fine in Chrome 118

Goukiesm
Автор

Whenever I implement an animation loop I always add key controls to start and stop the loop incase I accidentally cause a looping error. For this project I made a Game object with a "running" property, and 2 functions to start and stop (controlled by keys). You check if the game is running at the animate loop (return if not), and start animate() when starting again (along with setting game.running).

cloudzero