Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by 4t0m1c · Aug 07, 2013 at 01:34 PM · procedural generationendless runnerrandom gen

How do I proceduraly generate an environment around a sphere?

Hi

I'm creating an endless running game with an interesting perspective. The world is a sphere and i'm not sure how to go about generating a random environment (off the path and on the path within the 3 lanes) on the surface of the sphere.

Thanks

Jared

alt text

gameplay.jpg (80.6 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

5 Replies

· Add your reply
  • Sort: 
avatar image
7
Best Answer

Answer by aldonaletto · Aug 07, 2013 at 02:13 PM

For something like shown in the picture, you should create tileable meshes in a 3D editor. As the player moves, randomly select the next mesh and replace the older one as a child of the planet object. The trees and other details could also be randomly selected and childed to the meshes.

You could have segments corresponding to spherical wedges of about 90 degrees, for instance, like below:

alt text

Each new wedge could be a game object containing the mesh and with the details childed to it. The hierarchy could be as follows:

 Planet
   Wedge1
     Tree1
     Tree2
     Rock1
     Bush1
   Wedge2
     // wedge2 details
   Wedge3
     // wedge3 details
   Wedge4
     // wedge4 details


EDITED: If you want to use a simple sphere as the planet, things are easier. Paint a sphere with the path and the grass (you must create a suitable texture in an image editor), then rotate it when the player walks. Items like trees, rocks etc. may be created at Start and populate the planet near to the player. As the planet rotates and items pass the player, they may be "transplanted" to a new location ahead enough of the player.

The script below is an example on how to do this. The path region is delimited by the angle (-pathAngle..pathAngle) from the vertical, and the grass and items populate the region from (-grassAngle..grassAngle) from the vertical (path region excluded). When the up key is pressed, the planet rotates about X to simulate that the player is walking; as the planet rotates, items that pass the angle killAngle from the forward direction are moved to a new random position at bornAngle from the horizontal plane.

alt text

In order to use this script you must attach it to the player, then drag the planet object to planet, set radius to the radius of your planet and fill the prefabs array with the prefabs.

 var planet: Transform; // drag the planet here
 var radius: float = 20; // planet radius
 var vel: float = 6; // player speed - degrees per second
 var prefabs: Transform[]; // drag the item prefabs here
 var qntItems = 30; // how many items populate the scene
 var bornAngle: float = 0; // items born at this X angle
 var killAngle: float = 90; // items disappear after this angle
 var pathAngle: float = 10; // path angle from vertical
 var grassAngle: float = 45; // end of grass angle from vertical
 
 private var items: Transform[];
 
 function Start () {
     items = new Transform[qntItems];
     // populate planet
     for (var i=0; i<qntItems; i++){
         // create a random item
         var item = Instantiate(prefabs[Random.Range(0, prefabs.Length)]);
         MoveItem(item, Random.Range(bornAngle, killAngle)); // move it to a random position
         item.parent = planet; // child item to the planet
         items[i] = item;
     }
 }
 
 function Update () {
     // rotate planet according to up/down arrow keys
     var vAxis: float = Input.GetAxis("Vertical");
     planet.Rotate(-vAxis*vel*Time.deltaTime, 0, 0);
     if (vAxis > 0.1){ // if moving...
         animation.CrossFade("walk"); // play "walk" animation
     } else {
         animation.CrossFade("idle"); // else play "idle"
     }
     for (var i = 0; i < qntItems; i++){
         // if item passed the kill angle from Z axis...
         if (Vector3.Angle(items[i].up, Vector3.forward) > killAngle){
             // replant it at the born angle, at random position
             MoveItem(items[i], bornAngle);
         }
     }
 }
 
 // Move item to a random position in the grass, at elevation angleX
 function MoveItem(item: Transform, angleX: float) {
     var angleY: float;
     if (Random.value < 0.5){ // randomly select left or right sides
         angleY = Random.Range(-grassAngle, -pathAngle);
     } else {
         angleY = Random.Range(pathAngle, grassAngle);
     }
     // calculate new item up direction
     var dir = Quaternion.Euler(0, angleY, 0) * Vector3.forward;
     dir = Quaternion.Euler(-angleX, 0, 0) * dir;
     // set item position and rotation
     item.position = planet.position + radius * dir;
     item.rotation = Quaternion.FromToRotation(Vector3.up, dir);
 }


EDITED2: This version includes random size, rotation and color for the world assets, and continuous pickup items generation. The pickups are generated at a 0 born angle, and with a separation of pickupAngle degrees: when the planet rotates pickupAngle from the born angle, a new pickup is generated. The pickups must be collected by the player, since the code doesn't takes care of them after creation - if not collected and destroyed, they will crowd the path after a few turns:

 var planet: Transform; // drag the planet here
 var radius: float = 20; // planet radius
 var vel: float = 6; // player speed - degrees per second
 var prefabs: Transform[]; // drag the item prefabs here
 var qntItems = 30; // how many items populate the scene
 var bornAngle: float = 0; // items born at this X angle
 var killAngle: float = 90; // items disappear after this angle
 var pathAngle: float = 10; // path angle from vertical
 var grassAngle: float = 45; // end of grass angle from vertical
 var pickupPrefabs: Transform[]; // drag the pickup prefabs here
 var pickupAngle: float = 7; // degrees between pickups
 var pickupHeight: float = 1; // pickup height above ground
 
 private var items: Transform[];
 private var lastPickup: Transform; // last pickup created
 
 function Start () {
     items = new Transform[qntItems];
     // populate planet
     for (var i=0; i<qntItems; i++){
         // create a random item
         var item = Instantiate(prefabs[Random.Range(0, prefabs.Length)]);
         MoveItem(item, Random.Range(bornAngle, killAngle)); // move it to a random position
         item.parent = planet; // child item to the planet
         items[i] = item;
     }
     lastPickup = CreatePickup();
 }
 
 function Update () {
     // rotate planet according to up/down arrow keys
     var vAxis: float = Input.GetAxis("Vertical");
     if (vAxis > 0.1){ // if moving forward...
         planet.Rotate(-vAxis*vel*Time.deltaTime, 0, 0); // rotate planet
         animation.CrossFade("walk"); // play "walk" animation
     } else {
         animation.CrossFade("idle"); // else play "idle"
     }
     for (var i = 0; i < qntItems; i++){
         // if item passed the kill angle from Z axis...
         if (Vector3.Angle(items[i].up, Vector3.forward) > killAngle){
             // replant it at the born angle, at random position
             MoveItem(items[i], bornAngle);
         }
     }
     if (Vector3.Angle(lastPickup.up, Vector3.forward) > pickupAngle){
         lastPickup = CreatePickup();
     }
 }
 
 // Move item to a random position in the grass, at elevation angleX
 function MoveItem(item: Transform, angleX: float) {
     var angleY: float;
     if (Random.value < 0.5){ // randomly select left or right sides
         angleY = Random.Range(-grassAngle, -pathAngle);
     } else {
         angleY = Random.Range(pathAngle, grassAngle);
     }
     // calculate new item up direction
     var dir = Quaternion.Euler(0, angleY, 0) * Vector3.forward;
     dir = Quaternion.Euler(-angleX, 0, 0) * dir;
     // set item position and rotation
     item.position = planet.position + radius * dir;
     item.rotation = Quaternion.FromToRotation(Vector3.up, dir);
     // set random size and rotation about Y 
     item.Rotate(0, Random.Range(0, 360), 0);
     item.localScale = Random.Range(0.4, 1.5)*Vector3.one;
     // set a random color
     var rndColor: Vector4 = Random.insideUnitSphere;
     var rndr = item.GetComponentInChildren(Renderer);
     rndr.material.color = rndColor;
 }
 
 function CreatePickup(){ // create pickup in front of the planet
     var pickup = Instantiate(pickupPrefabs[Random.Range(0, pickupPrefabs.Length)]);
     pickup.parent = planet;
     pickup.up = Vector3.forward;
     pickup.position = planet.position + Vector3.forward * (radius + pickupHeight);
     return pickup;
 }

If some pickups may not be collected by the player, all pickups should have a script attached that would suicide them after passing back the player - something like this:

 function Update(){ // destroy pickup when at more than 90 degrees from born angle:
     if (Vector3.Angle(transform.up, Vector3.forward) > 90) Destroy(gameObject);
 }

If one wants irregular spacing between pickups, a possible solution is to include a number of "empty pickups" in the pickupPrefabs array - empty objects with the suicide script above: they would do nothing but occupy the space of real pickups.


wedges.png (5.5 kB)
randomplanet.png (7.1 kB)
Comment
Add comment · Show 9 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Xtro · Aug 07, 2013 at 02:16 PM 0
Share

I think he wants to generate the objects, not the path.

avatar image 4t0m1c · Aug 07, 2013 at 08:10 PM 0
Share

Thanks very much for the speedy response. So going back to my question: how would I randomly spawn and despawn assets on the surface, whether it be the entire sphere or segments? And is there something like a weight painting function that I an use maybe to separate the spawn area for the environment and for the track.

avatar image aldonaletto · Aug 08, 2013 at 12:42 AM 1
Share

@Xtro, hope you're right: it would be much easier this way!

avatar image Xtro · Aug 08, 2013 at 02:34 AM 0
Share

I know it's the most advanced method but it's the easiest to start with. If you prove your game design, then maybe you can build an advanced system.

avatar image 4t0m1c · Aug 18, 2013 at 11:35 AM 0
Share

@aldonaletto, you my friend are a genius! The script works beautifully, the only issue is scale and rotation. On my trees, the scale needs to be at 2.5 rather than 1 and for my little plants, the rotation puts them 90 deg on the x making them face sideways. Also how would I go about, varying the spatial distance between the elements? And how would I make the z rotation random? Thanks a lot for all your help!! alt text

size-corrections.jpg (155.3 kB)
Show more comments
avatar image
2

Answer by meat5000 · Aug 10, 2013 at 02:09 PM

At the start() store the initial position of the character in Vector3. Keep track of the angle difference between the current position and start position. Store this angle as a Quaternion and you can use it to modify a Vector3 directly.

UpdatedVector = Quaternion * OldVector

This will allow you to spawn anything using instantiate relative to the player using that Quaternion, provided the initial position on the object is similar. Add a Random.range to it to make an object spawn randomly within the area. Use the same angle to rotate the clone in the instantiate() function to keep its feet on the floor upon spawn. Parent the spawned object in script to the world to allow it to follow the transform of the rotating world. When objects drop off camera view behind the player, destroy them.

Here is something I've used for instantiating a cube around a circle. A separate "Governor" script decides the next position. Maybe you can draw some inspiration from it.

 private var guv : GameObject;
 public var original : GameObject;
 
 static var cloneCount : int = 0;
 var turnAngle : float = 18.0;
 var nextPos : int = 0;
 
 var timeKeeper : float = 0.0;
 var spawnTime : float = 3.0;
 var placement : Vector3 = Vector3(0,88,0);
 var newPlacement : Vector3;
   
 
 @HideInInspector
 public var clone : GameObject;
 
 function Start ()
 {
     guv = GameObject.Find("Governor");
     //original = GameObject.Find("Cube");
     original = GameObject.Find("CrazyCube");
     turnAngle = guv.GetComponent(Governor).stepAngle;
     spawnTime = guv.GetComponent(Governor).spawnTiming;
     nextPos = guv.GetComponent(Governor).nextPlace;
 }
 
 function FixedUpdate ()
 {
     turnAngle = guv.GetComponent(Governor).stepAngle;
     nextPos = guv.GetComponent(Governor).nextPlace;
     spawnTime = guv.GetComponent(Governor).spawnTiming;
     timeKeeper += Time.fixedDeltaTime;
     if (timeKeeper >= spawnTime)
     {
         newPlacement = Quaternion.Euler(0,0,turnAngle*nextPos) * placement;
         clone = Instantiate(original, newPlacement, Quaternion.Euler(0,0,turnAngle*nextPos));
         cloneCount += 1;
         clone.name = ("clone"+cloneCount.ToString());
         
         timeKeeper = 0;
     }
 }
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image 4t0m1c · Aug 11, 2013 at 09:51 PM 0
Share

Thanks very much, this helped me out 

avatar image meat5000 ♦ · Aug 12, 2013 at 06:44 PM 0
Share

You are welcome :)

( :P)

avatar image
0

Answer by sacredgeometry · Aug 10, 2013 at 01:31 PM

The easiest way that doesn't involve any maths is to use a parented objects rotational pivot. To explain I will give you a little stepped procedure that you can replicate programatically.

  1. Create two cubes and offset one from the other.

  2. Parent one to the other

  3. Rotate the parent cube so that the child follows its rotation

  4. unparent the child

You will notice that it is still in the same position, you could do this with a center pivot to a sphere ... the only real problem is uneaven terrain but I guess you could fix this with ray casting.

This is a simple non-mathematic solution :)

Other than that (sorry i had the wrong link in my copy/paste buffer ) ...

http://entitycrisis.blogspot.co.uk/2011/02/uniform-points-on-sphere.html

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by glitchy · Aug 07, 2013 at 02:15 PM

You could split your map up into pre-made segments then randomly spawn and connect them together. What i would do is think of the world like a pie that you are running around on the edge of. As you pass a piece of the pie and can no longer see it, replace it with another random piece.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by Xtro · Aug 07, 2013 at 01:56 PM

I think easiest way is to set a lot of preset locations via empty gameobjects. Than you can crete the obstacles or bonuses on those locations.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

19 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Endless "Falling" Game - Background generation 2 Answers

Creating random seeds and saving them (procedural generation)Universe 1 Answer

How to make a race track similar to audiosurf? 0 Answers

How to create endless terrain... 0 Answers

Generating a tiled world with roads, possibly using a 2D array? (C#) 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges