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

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:

[14002-wedges.png*_|14002]

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.

[14141-randomplanet.png*_|14141]

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 *= item;*
  • }*
    }

function Update () {

  • // rotate planet according to up/down arrow keys*
  • var vAxis: float = Input.GetAxis(“Vertical”);*
    _ planet.Rotate(-vAxisvelTime.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*.up, Vector3.forward) > killAngle){_
_
// replant it at the born angle, at random position*_
_ MoveItem(items*, 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 = 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(-vAxisvelTime.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*.up, Vector3.forward) > killAngle){*
// replant it at the born angle, at random position
MoveItem(items*, 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.
*
*

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;
	}
}

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.

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.

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 :slight_smile:

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