In my unity project i have 3 scenes.
Title
Play
Over
For achieving the flow Title -> Play -> Over. I had to start the game from Over scene. Over -> Title -> Play -> Over .. I don't want this. I want it to work when i start the game from Title scene. On doing so i am unable to change from Play -> Over.
for Title scene
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadSceneOnInput : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetAxis("Submit") == 1) {
SceneManager.LoadScene("Play");
}
}
}
for Over Scene
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameOverInput : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetAxis("Submit") == 1) {
SceneManager.LoadScene("Title");
}
}
}
Play's script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelGenerator : MonoBehaviour {
public GameObject floorPrefab;
public GameObject wallPrefab;
public GameObject ceilingPrefab;
public GameObject characterController;
public GameObject floorParent;
public GameObject wallsParent;
// allows us to see the maze generation from the scene view
public bool generateRoof = true;
// number of times we want to "dig" in our maze
public int tilesToRemove = 50;
public int mazeSize;
// spawns at the end of the maze generation
public GameObject pickup;
// this will determine whether we've placed the character controller
private bool characterPlaced = false;
// 2D array representing the map
private bool[,] mapData;
// we use these to dig through our maze and to spawn the pickup at the end
private int mazeX = 4, mazeY = 1;
// Use this for initialization
void Start () {
// initialize map 2D array
mapData = GenerateMazeData();
// create actual maze blocks from maze boolean data
for (int z = 0; z < mazeSize; z++) {
for (int x = 0; x < mazeSize; x++) {
if (mapData[z, x]) {
CreateChildPrefab(wallPrefab, wallsParent, x, 1, z);
CreateChildPrefab(wallPrefab, wallsParent, x, 2, z);
CreateChildPrefab(wallPrefab, wallsParent, x, 3, z);
} else if (!characterPlaced) {
// place the character controller on the first empty wall we generate
characterController.transform.SetPositionAndRotation(
new Vector3(x, 1, z), Quaternion.identity
);
// flag as placed so we never consider placing again
characterPlaced = true;
CreateChildPrefab(floorPrefab, floorParent, x, 0, z);
}
//create floor and ceiling
if(mapData[z, x]){
CreateChildPrefab(floorPrefab, floorParent, x, 0, z);
}else{
if((z > 0 && z < mazeSize - 1) && (x > 0 && x < mazeSize - 1)){
if(!(Random.value > 0.8)){
CreateChildPrefab(floorPrefab, floorParent, x, 0, z);
}
}
}
if (generateRoof) {
CreateChildPrefab(ceilingPrefab, wallsParent, x, 4, z);
}
}
}
// spawn the pickup at the end
var myPickup = Instantiate(pickup, new Vector3(mazeX, 1, mazeY), Quaternion.identity);
myPickup.transform.localScale = new Vector3(0.25f, 0.25f, 0.25f);
}
void Update() {
if(characterController.transform.position.y < -5){
SceneManager.LoadScene("Over");
}
}
// generates the booleans determining the maze, which will be used to construct the cubes
// actually making up the maze
bool[,] GenerateMazeData() {
bool[,] data = new bool[mazeSize, mazeSize];
// initialize all walls to true
for (int y = 0; y < mazeSize; y++) {
for (int x = 0; x < mazeSize; x++) {
data[y, x] = true;
}
}
// counter to ensure we consume a minimum number of tiles
int tilesConsumed = 0;
// iterate our random crawler, clearing out walls and straying from edges
while (tilesConsumed < tilesToRemove) {
// directions we will be moving along each axis; one must always be 0
// to avoid diagonal lines
int xDirection = 0, yDirection = 0;
if (Random.value < 0.5) {
xDirection = Random.value < 0.5 ? 1 : -1;
} else {
yDirection = Random.value < 0.5 ? 1 : -1;
}
// random number of spaces to move in this line
int numSpacesMove = (int)(Random.Range(1, mazeSize - 1));
// move the number of spaces we just calculated, clearing tiles along the way
for (int i = 0; i < numSpacesMove; i++) {
mazeX = Mathf.Clamp(mazeX + xDirection, 1, mazeSize - 2);
mazeY = Mathf.Clamp(mazeY + yDirection, 1, mazeSize - 2);
if (data[mazeY, mazeX]) {
data[mazeY, mazeX] = false;
tilesConsumed++;
}
}
}
return data;
}
// allow us to instantiate something and immediately make it the child of this game object's
// transform, so we can containerize everything. also allows us to avoid writing Quaternion.
// identity all over the place, since we never spawn anything with rotation
void CreateChildPrefab(GameObject prefab, GameObject parent, int x, int y, int z) {
var myPrefab = Instantiate(prefab, new Vector3(x, y, z), Quaternion.identity);
myPrefab.transform.parent = parent.transform;
}
}
Related
Background:
I'm trying to set up a system to spawn in a set amount of GameObjects, defined in the Menu Scene loaded before the Main Scene, into my game. I do this by running 3 for loops for the length of however many objects the user inputs in the Menu, with each loop run instantiating a copy of the Prefab.
The Problem:
Whenever the Main Scene (Game Scene) is loaded from the menu, it always spawns at least 1 of each Prefab even if the number is defined as 0 or null. This is an issue, as it always adds a copy of each Prefab on top of the user defined amount.
Partial Menu Image:
Menu segment for inputting values
Images of Issue:
Spawned assets in scene
Assets in navigator
So far I've tried setting up multiple Debug.Log(); -s throughout all the scripts that handle the numbers that are eventually parsed and passed to the spawning script itself (Data Managers, scriptable objs...) , as well as inside the spawning script itself. All the logs return the values as 0 and as such nothing should be spawning.
Code of the Spawner Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PawnSpawner : MonoBehaviour
{
[SerializeField] VarManager VarManager;
[SerializeField] GameObject Pawn;
[SerializeField] GameObject InfPawn;
[SerializeField] GameObject VaxPawn;
private int? totPawns;
private int? defPawns;
private int? infPawns;
private int? vaxPawns;
private void Awake()
{
VarManager = GameObject.Find("GameManager").GetComponent<VarManager>();
totPawns = VarManager.totalPawns;
defPawns = VarManager.uninfectedPawnAmount;
infPawns = VarManager.infectedPawnAmount;
vaxPawns = VarManager.vaccinatedPawnAmount;
}
// Start is called before the first frame update
void Start()
{
if(defPawns != 0 || defPawns != null)
{
for (int i = 0; i <= defPawns; i++)
{
int x = UnityEngine.Random.Range(-300, 301);
int y = UnityEngine.Random.Range(-300, 301);
GameObject D_Pawn = Instantiate(Pawn, new Vector3(x, y, 0), Quaternion.identity);
}
}
if(infPawns != 0 || infPawns != null)
{
for (int i = 0; i <= infPawns; i++)
{
int x = UnityEngine.Random.Range(-300, 301);
int y = UnityEngine.Random.Range(-300, 301);
GameObject I_Pawn = Instantiate(InfPawn, new Vector3(x, y, 0), Quaternion.identity);
}
}
if (vaxPawns != 0 || vaxPawns != null)
{
for (int i = 0; i <= vaxPawns; i++)
{
int x = UnityEngine.Random.Range(-300, 301);
int y = UnityEngine.Random.Range(-300, 301);
GameObject V_Pawn = Instantiate(VaxPawn, new Vector3(x, y, 0), Quaternion.identity);
}
}
}
// Update is called once per frame
void Update()
{
Destroy(this);
}
private void OnDestroy()
{
Debug.Log("---PAWN SPAWNER HAS FULLY EXECUTED SPAWNING SEQUENCE---");
Debug.Log("TOTAL PAWNS SPAWNED:" + totPawns);
Debug.Log("Default Pawns:" + defPawns);
Debug.Log("Infected Pawns:" + infPawns);
Debug.Log("Vaccinated Pawns:" + vaxPawns);
Debug.Log("---REMOVING SELF---");
}
}
So I want to make a map generator and have a prefab for a tile. But I want to make more tiles which it randomly chooses from.
How can I make it that tilePrefab is chosen randomly every time from an array of prefabs?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public Transform tilePrefab; //This is the part which I want to be random
public Vector2 mapSize;
private void Start()
{
GenerateMap();
}
public void GenerateMap()
{
for (int x = 0; x < mapSize.x; x++)
{
for (int y = 0; y < mapSize.y; y++)
{
Vector3 tilePosition = new Vector3(-mapSize.x / 2 + 0.5f + x, 0,-mapSize.y / 2 + 0.5f + y);
Transform newTile = Instantiate(tilePrefab, tilePosition, Quaternion.Euler(Vector3.right * 360)) as Transform;
}
}
}
}
I want that tilePrefab is chosen randomly every time a tile gets generated.
Have an array that holds all the tile prefabs. Randomly choose an index for your new tile.
Transform newTile = Instantiate(tilePrefabs[Random.Range(0, tilePrefabs.Length - 1), tilePosition, Quaternion.Euler(Vector3.right * 360)) as Transform;
I have 3 scripts one duplicate a script and the third should get created objects but I can't get this objects. How can I get the objects?
The first script is Generate Stairs Units. This script is attached to a empty GameObject.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateStairsUnits : MonoBehaviour
{
[Header("Stairs Units Prefab")]
public GameObject stairsUnitsPrefab;
[Space(5)]
[Header("Settings")]
[Range(1, 20)]
public int numberOfUnits = 1;
public static GameObject Unit;
private int oldNumberOfUnits = 0;
private List<GameObject> units = new List<GameObject>();
// Use this for initialization
void Start ()
{
oldNumberOfUnits = numberOfUnits;
var unitsParent = GameObject.Find("Stairs Units");
for (int i = 0; i < numberOfUnits; i++)
{
Unit = Instantiate(stairsUnitsPrefab, unitsParent.transform);
Unit.name = "Stairs " + i.ToString();
units.Add(Unit);
Unit.AddComponent<MoveObjects>();
}
}
// Update is called once per frame
void Update ()
{
}
}
The GenerateStairsUnits script duplicate a prefab of the second script Generate Stairs:
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class GenerateStairs : MonoBehaviour
{
[Header("Stairs Prefb")]
public GameObject stairsPrefab;
[Space(5)]
[Header("Platforms")]
public bool addPlatforms = false;
public GameObject platformsPrefab;
[Space(5)]
[Header("Settings")]
public float delay = 3;
public int stairsNumber = 5;
public Vector3 stairsStartPosition;
public Vector3 stairSize;
public Vector3 stairsSize;
public float stepWidthFactor = 1f;
public GameObject moveobjects;
private Vector3 stairsPosition;
private GameObject stairsParent;
// Use this for initialization
void Start()
{
moveobjects = GameObject.Find("Move Objects");
stairsParent = new GameObject();
stairsParent.name = "Stairs";
stairsParent.transform.parent = GenerateStairsUnits.Unit.transform;
StartCoroutine(BuildStairs());
}
// Update is called once per frame
void Update()
{
}
private IEnumerator BuildStairs()
{
for (int i = 1; i <= stairsNumber; i++)
{
stairsPosition = new Vector3(
stairsStartPosition.x,
stairsStartPosition.y + (i * stairsSize.y),
stairsStartPosition.z + (i * stairsSize.y) * stepWidthFactor);
GameObject stair = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stair.tag = "Stair";
stair.transform.parent = transform;
stair.transform.localScale = stairSize;
yield return new WaitForSeconds(delay);
}
}
}
The GenerateStairsUnits also add as component the third script Move Objects:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class MoveObjects : MonoBehaviour
{
public List<GameObject> objectsToMove = new List<GameObject>();
public AnimationCurve curve;
public float stepsPerSecond = 1f;
public bool changeDirection = false;
private Vector3 trackStart;
private Vector3 trackEnd;
private Vector3 horizontalTravel;
private float verticalTravel;
private float divisor;
private float phase = 0f;
// Use this for initialization
public void Init()
{
if (curve == null)
{
curve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1));
}
curve.preWrapMode = WrapMode.Clamp;
curve.postWrapMode = WrapMode.Clamp;
trackStart = objectsToMove[0].transform.position;
int count = objectsToMove.Count;
var span = objectsToMove[count - 1].transform.position - trackStart;
divisor = 1f / count;
horizontalTravel = (count + 1) * span * divisor;
horizontalTravel.y = 0f;
verticalTravel = span.y;
trackEnd = trackStart + (count + 1) * span / count;
}
// Update is called once per frame
void Update()
{
if (objectsToMove != null && objectsToMove.Count > 0 && curve != null)
{
AnimationCurve();
}
}
private void AnimationCurve()
{
phase = Mathf.Repeat(phase + stepsPerSecond * divisor * Time.deltaTime, 1f);
for (int i = 0; i < objectsToMove.Count; i++)
{
float t = Mathf.Repeat(phase + i * divisor, 1f);
// Get the height of the curve at this step.
float curveHeight = curve.Evaluate(t) * verticalTravel;
if (changeDirection)
{
objectsToMove[i].transform.position = trackStart // First step
- horizontalTravel * t // evenly spaced horizontal
+ curveHeight * Vector3.up; // curving vertical
}
else
{
objectsToMove[i].transform.position = trackStart // First step
+ horizontalTravel * t // evenly spaced horizontal
+ curveHeight * Vector3.up; // curving vertical
}
}
}
private void StraightLineTrack()
{
float divisor = 1f / objectsToMove.Count;
// Compute the current phase of the escalator,
// from 0 (1st step at track start) to 1 (1st step at track end)
phase = Mathf.Repeat(phase + stepsPerSecond * divisor * Time.deltaTime, 1f);
// Place each step a proportional distance along the track.
for (int i = 0; i < objectsToMove.Count; i++)
{
float t = Mathf.Repeat(phase + i * divisor, 1f);
objectsToMove[i].transform.position = Vector3.Lerp(trackStart, trackEnd, t);
}
}
}
Now the problem:
After duplicating the GenerateStairs and creating stairs for each Stairs Unit and adding the Move Objects component the result is:
In the Hierarchy I have empty GameObject name Stairs Units. Under Stairs Units there are the Units Stairs 0, Stairs 1, Stairs 2, Stairs 3, Stairs 4. And under each Stairs there are the Stairs.
Each Unit for example Stair 0 have also attached the Move Objects script.
Now my problem is how to get the stairs of each unit to the Move Objects objectsToMove List.
In the Move Objects I have a List name objectsToMove. For example under Stairs 0 there are 10 stairs I need to get this 10 stairs to the objectsToMove of Stairs 0. Then the next 10 stairs of the Stairs 1 and so on. But I can't figure out how to add the stairs of each unit to the objectsToMove.
In the end the objectsToMove that what should move the stairs of each Stairs Unit.
Since your Stairs N gameobject attaches two scripts GenerateStairs and MoveObjects on it, you can get the MoveObjects's reference by calling GetComponent before generating the Stairs and pass it to the BuildStairs function.
void Start()
{
...
MoveObjects moveObjects = gameObject.GetComponent<MoveObjects>();
StartCoroutine(BuildStairs(moveObjects));
}
By getting the MoveObjects's reference, you can then pass this reference into your BuildStairs function and add those generating stairs into list objectsToMove inside MoveObjects.
Modify the function and pass MoveObjects like below:
private IEnumerator BuildStairs(MoveObjects moveObjects)
{
...
moveObjects.objectsToMove.add (stair);
...
}
About GetComponent.
update...
First Class
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Wave
{
public GameObject enemyPrefab;
public float spawnInterval = 2;
public int maxEnemies = 20;
}
public class SpawnEnemy : MonoBehaviour
{
public GameObject[] waypoints;
public GameObject testEnemyPrefab;
public Wave[] waves;
public int timeBetweenWaves = 5;
private GameManagerBehavior gameManager;
private float lastSpawnTime;
private int enemiesSpawned = 0;
// Use this for initialization
void Start()
{
lastSpawnTime = Time.time;
gameManager =
GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
}
// Update is called once per frame
void Update()
{
// 1 Get the index of the current wave, and check if it’s the last one.
int currentWave = gameManager.Wave;
if (currentWave < waves.Length)
{
// 2 If so, calculate how much time passed since the last enemy spawn and whether it’s time to spawn an enemy. Here you consider two cases.
// If it’s the first enemy in the wave, you check whether timeInterval is bigger than timeBetweenWaves.
// Otherwise, you check whether timeInterval is bigger than this wave’s spawnInterval. In either case, you make sure you haven’t spawned all the enemies for this wave.
float timeInterval = Time.time - lastSpawnTime;
float spawnInterval = waves[currentWave].spawnInterval;
if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
timeInterval > spawnInterval) &&
enemiesSpawned < waves[currentWave].maxEnemies)
{
// 3 If necessary, spawn an enemy by instantiating a copy of enemyPrefab. You also increase the enemiesSpawned count.
lastSpawnTime = Time.time;
GameObject newEnemy = (GameObject)
Instantiate(waves[currentWave].enemyPrefab);
newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
newEnemy.GetComponent<MoveEnemy>().JiggleWaypoints();
enemiesSpawned++;
}
// 4 You check the number of enemies on screen. If there are none and it was the last enemy in the wave you spawn the next wave.
// You also give the player 10 percent of all gold left at the end of the wave.
if (enemiesSpawned == waves[currentWave].maxEnemies &&
GameObject.FindGameObjectWithTag("Enemy") == null)
{
gameManager.Wave++;
gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f);
enemiesSpawned = 0;
lastSpawnTime = Time.time;
}
// 5 Upon beating the last wave this runs the game won animation.
}
else {
gameManager.gameOver = true;
GameObject gameOverText = GameObject.FindGameObjectWithTag("GameWon");
gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
}
}
}
Second Class
using UnityEngine;
using System.Collections;
public class MoveEnemy : MonoBehaviour
{
[System.NonSerialized]
public GameObject[] waypoints;
private int currentWaypoint = 0;
private float lastWaypointSwitchTime;
public float speed = 1.0f;
// Use this for initialization
void Start()
{
lastWaypointSwitchTime = Time.time;
}
// Update is called once per frame
void Update()
{
// 1
Vector3 startPosition = waypoints[currentWaypoint].transform.position;
Vector3 endPosition = waypoints[currentWaypoint + 1].transform.position;
// 2
float pathLength = Vector3.Distance(startPosition, endPosition);
float totalTimeForPath = pathLength / speed;
float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
gameObject.transform.position = Vector3.Lerp(startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
// 3
if (gameObject.transform.position.Equals(endPosition))
{
if (currentWaypoint < waypoints.Length - 2)
{
// 3.a
currentWaypoint++;
lastWaypointSwitchTime = Time.time;
RotateIntoMoveDirection();
}
else {
// 3.b
Destroy(gameObject);
AudioSource audioSource = gameObject.GetComponent<AudioSource>();
AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
//<< deduct health
GameManagerBehavior gameManager =
GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
gameManager.Health -= 1;
//>>
}
}
}
public void JiggleWaypoints()
{
for (int i = 1; i < waypoints.Length; i++)
{
waypoints[i].transform.position = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 3), waypoints[i].transform.position.y + Random.Range(-3, 3), 0);
}
}
private void RotateIntoMoveDirection()
{
//1 It calculates the bug’s current movement direction by subtracting the current waypoint’s position from that of the next waypoint.
Vector3 newStartPosition = waypoints[currentWaypoint].transform.position;
Vector3 newEndPosition = waypoints[currentWaypoint + 1].transform.position;
Vector3 newDirection = (newEndPosition - newStartPosition);
//2 It uses Mathf.Atan2 to determine the angle toward which newDirection points, in radians, assuming zero points to the right.
// Multiplying the result by 180 / Mathf.PI converts the angle to degrees.
float x = newDirection.x;
float y = newDirection.y;
float rotationAngle = Mathf.Atan2(y, x) * 180 / Mathf.PI;
//3 Finally, it retrieves the child named Sprite and rotates it rotationAngle degrees along the z-axis.
// Note that you rotate the child instead of the parent so the health bar — you’ll add it soon — remains horizontal.
GameObject sprite = (GameObject)
gameObject.transform.FindChild("Sprite").gameObject;
sprite.transform.rotation =
Quaternion.AngleAxis(rotationAngle, Vector3.forward);
}
public float distanceToGoal()
{
float distance = 0;
distance += Vector3.Distance(
gameObject.transform.position,
waypoints[currentWaypoint + 1].transform.position);
for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++)
{
Vector3 startPosition = waypoints[i].transform.position;
Vector3 endPosition = waypoints[i + 1].transform.position;
distance += Vector3.Distance(startPosition, endPosition);
}
return distance;
}
}
Code is working 100% without errors, BUT....
After each spawn all objects get the same waypoint array. This can be seen on the screen as all objects jump to new waypoint in line together each time new object is spawned. I want the object which is already spawn to live life with it's own array of only once created waypoints.
You need to create a new array of waypoints each time you create one from the prefabricated object. You don't show your Instantiate method but I'm guessing that it has a line like this:
this.waypoints = prefab.waypoints;
This will mean that all object you create will share the same list of waypoints (as you've discovered).
What you need is something like this - assuming that the waypoints have X, Y, and Z properties):
this.waypoints = new GameObject[5];
for (int i = 0; i++ ; i < 5)
{
this.waypoints[i].X = prefab.waypoints[i].X;
this.waypoints[i].Y = prefab.waypoints[i].Y;
this.waypoints[i].Z = prefab.waypoints[i].Z;
}
(If you want your points to be a variable length you might want to consider using a list).
This means that each object has a list of unique points even if they start with the same values you can change each independently.
Based on ChrisFs' and Joe Blows' answers, do something like this in your MoveEnemy script:
private Vector3[] myWay;
public void JiggleWaypoints(GameObject[] waypoints)
{
myWay = new Vector3[waypoints.Length];
for(int i = 1; i < waypoints.Length; i++)
{
myWay[i] = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 4), waypoints[i].transform.position.y + Random.Range(-3, 4), 0);
}
}
myWay replaces the GameObject[].
In your SpawnEnemy script you do this:
GameObject e = (GameObject)Instantiate(enemyPrefab);
e.GetComponent<MoveEnemy>().JiggleWaypoints(waypoints);
I'm learning unity and I'm recreating a game of mine I wrote in XNA in unity.
I have the main camera script to adjust itself to the position of the player transform, but I want it to be limited to the map bounds.
That gives me 2 problems:
1) Add the script portion that limits the camera movement to the bounds of the map
2) Get the actual map bounds from the mass of prefabs that are thrown on the map.
This is another post of mine regarding collision with the walls that doesn't work (if you'd like, go in the post, as I would love to have some help with the collision problem as well)
This is how the camera looks with size 4.5 when I roughly centered it on the map:
This is how the camera looks with size 4.5 when it's simply showing some part of the map and is out of it
When I lower the camera size to 3, it looks roughly like so:
There are 3 things to do based on that:
1) Limit the camera size not to be able to be bigger than the map width
2) Limit the camera movement not to be able to move outside of the map
2.1) To be able to do (2) I need to get the map bounds.
To generate the map, I use the scripts from the tutorial specified in my other post, and changed to my needs:
using System.Collections.Generic;
using UnityEngine;
namespace Assets.Scripts
{
internal enum BlockPosition
{
None = -1,
Top = 0,
Bottom,
Left,
Right,
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
public class BoardManager : MonoBehaviour
{
private const int BORDER_COL = -1;
public int columns = 15;
public int rows = 15;
// Up, Down, Left, Right, TopLeft, TopRight, BottomLeft, BottomRight
public GameObject[] wallTiles;
public GameObject[] floorTiles;
private readonly List<Vector3> floorPositions = new List<Vector3>();
private Transform boardHolder;
private Transform floorHolder;
private Transform wallsHolder;
private void InitializeFloorPositionsList()
{
floorPositions.Clear();
for (int i = 0; i < columns; ++i)
{
for (int j = 0; j < rows; ++j)
{
floorPositions.Add(new Vector3(i, j, 0f));
}
}
}
/// <summary>
/// Gets the BlockPosition based on where on the wall grid the block is
/// </summary>
/// <param name="row">Row of the block</param>
/// <param name="col">Column of the block</param>
/// <returns>BlockPosition representing the position of the wall, or BlockPosition.None if it's a center block(a floor)</returns>
private BlockPosition GetBlockIndex(int row, int col)
{
///////////
// 1 2 3 //
// 4 5 6 // Number represents position in map
// 7 8 9 //
///////////
if (row == BORDER_COL)
{
if (col == BORDER_COL)
return BlockPosition.BottomLeft; // 7
if (col == columns)
return BlockPosition.BottomRight; // 9
return BlockPosition.Bottom; // 8
}
if (row == rows)
{
if (col == BORDER_COL)
return BlockPosition.TopLeft; // 1
if (col == columns)
return BlockPosition.TopRight; // 3
return BlockPosition.Top; // 2
}
if (col == BORDER_COL)
return BlockPosition.Left; // 4
if (col == columns)
return BlockPosition.Right; // 6
return BlockPosition.None; // 5
}
private void SetUpWalls()
{
boardHolder = new GameObject("Board").transform;
floorHolder = new GameObject("Floors").transform;
floorHolder.parent = boardHolder;
wallsHolder = new GameObject("Walls").transform;
wallsHolder.parent = boardHolder;
for (int col = BORDER_COL; col < columns + 1; col++)
{
for (int row = BORDER_COL; row < rows + 1; row++)
{
BlockPosition pos = GetBlockIndex(row, col);
if (pos == BlockPosition.None) continue;
GameObject toInstantiate = wallTiles[(int)pos];
GameObject instance =
Instantiate(toInstantiate, new Vector3(col, row, 0f), Quaternion.identity) as GameObject;
instance.transform.parent = wallsHolder;
}
}
}
private Vector3 RandomPosition()
{
int randomIndex = Random.Range(0, floorPositions.Count);
Vector3 position = floorPositions[randomIndex];
floorPositions.RemoveAt(randomIndex);
return position;
}
private void LayoutObjectsAtRandom(GameObject[] objects, int amount, Transform parent)
{
for (int i = 0; i < amount; ++i)
{
Vector3 position = RandomPosition();
GameObject instantiatedObject = objects[Random.Range(0, objects.Length)];
GameObject instantiated = Instantiate(instantiatedObject, position, Quaternion.identity) as GameObject;
instantiated.transform.parent = parent;
}
}
/// <summary>
/// Sets up the floors and the extraWalls
/// </summary>
/// <param name="extraWalls">for dev purposes, amount extra walls to be spreaaround the map</param>
public void SetUpScene(int extraWalls)
{
InitializeFloorPositionsList();
SetUpWalls();
LayoutObjectsAtRandom(wallTiles, extraWalls, wallsHolder);
LayoutObjectsAtRandom(floorTiles, floorPositions.Count, floorHolder);
}
}
}
As you can see, I followed the tutorial and eventually there's a Transform that holds all the instantiated map parts - it's called "Board" and it holds two other Transforms called "Floors" and "Walls", holding the floors and the walls.
How would you manage to solve those 3 problems I stated above?
I'm just a beginner at Unity, I'm just a C#/C++ developer so naturally XNA was simpler for me because it was a lot more code-centered than unity.
Edit: this is the CameraController script:
using UnityEngine;
namespace Assets.Scripts
{
public class CameraController : MonoBehaviour
{
public Transform player;
public Vector2 margin, smoothing;
public bool IsFollowing { get; set; }
public void Start()
{
IsFollowing = true;
}
public void Update()
{
var x = transform.position.x;
var y = transform.position.y;
if (IsFollowing)
{
if (Mathf.Abs(x - player.position.x) > margin.x)
x = Mathf.Lerp(x, player.position.x, smoothing.x * Time.deltaTime);
if (Mathf.Abs(y - player.position.y) > margin.y)
y = Mathf.Lerp(y, player.position.y, smoothing.y * Time.deltaTime);
}
transform.position = new Vector3(x, y, transform.position.z);
}
}
}