I am using Unity 3D engine to make a 2D game. I want to create endlessly repeating terrain. I got it to repeat seamlessly, except for the fact that sometimes two terrains will spawn at once. It happens randomly and without any good reason. Any help?
This is my terrain respawn code:
using UnityEngine;
using System.Collections;
using PlayerPrefs = GamePlayerPrefs;
public class SelfTerrainSpawn : MonoBehaviour {
// terrain references
public GameObject first;
public GameObject second;
public GameObject third;
public GameObject fourth;
public GameObject fifth;
public GameObject sixth;
public GameObject seventh;
public float spawnXPos = 0.0f;
public float respawnCoordinate = 30.4f;
public float respawnTriggerCoordinate = -21.7f;
public bool canSpawn = true;
public bool starting = true;
public float random;
void Start() {
this.gameObject.transform.position = new Vector2 (0.0f, 31.4f);
this.gameObject.transform.eulerAngles = new Vector3 (0, 0, 90.0f);
}
void Update()
{
// if the camera is farther than the number last position minus 16 terrain is spawned
// a lesser number may make the terrain 'pop' into the scene too early
// showing the player the terrain spawning which would be unwanted
if (this.gameObject.transform.position.y <= respawnTriggerCoordinate && canSpawn)
{
// turn off spawning until ready to spawn again
random = Random.Range(0,18);
SpawnTerrain (random);
canSpawn = false;
}
if (this.gameObject.transform.position.y <= respawnTriggerCoordinate - 10) {
Destroy (this.gameObject);
}
}
void SpawnTerrain(float rand) {
if ((rand == 0)) {
Instantiate (first, new Vector3 (respawnCoordinate, spawnXPos, 0), Quaternion.Euler (0, 0, 0));
}
if ((rand >= 1) && (rand <= 4)) {
Instantiate (second, new Vector3 (respawnCoordinate, spawnXPos, 0), Quaternion.Euler (0, 0, 0));
}
if ((rand >= 5) && (rand <= 8)) {
Instantiate (third, new Vector3 (respawnCoordinate, spawnXPos, 0), Quaternion.Euler (0, 0, 0));
}
if ((rand >= 9) && (rand <= 10)) {
Instantiate (fourth, new Vector3 (respawnCoordinate, spawnXPos, 0), Quaternion.Euler (0, 0, 0));
}
if ((rand >= 10) && (rand <= 13)) {
Instantiate (fifth, new Vector3 (respawnCoordinate, spawnXPos, 0), Quaternion.Euler (0, 0, 0));
}
if ((rand >= 13) && (rand <= 15)) {
Instantiate (sixth, new Vector3 (respawnCoordinate, spawnXPos, 0), Quaternion.Euler (0, 0, 0));
}
if ((rand >= 15) && (rand <= 18)) {
Instantiate (seventh, new Vector3 (respawnCoordinate, spawnXPos, 0), Quaternion.Euler (0, 0, 0));
}
}
}
This script is attached to the first terrain piece, inside of the game:
Click here to see an image of the game screen
It is also attached to the other two prefabs. Each of these prefabs also have a script that moves them down the screen slowly. Basically, when one's top reaches the top of the camera, another is supposed to spawn above the camera. Then it moves down and repeats. See that I used the canSpawn variable to make sure that it only spawns once. However, at random, two terrains will spawn on top of each other. Can anybody give me a solution to this problem?
When rand is 10, 13, or 15, you'll generate two terrains because your range checks overlap for those values.
Related
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour
{
public GameObject enemy;
float defaultSpawnTime = 1f;
float spawnTime = 1f;
float realTime = 4f;
void Start()
{
}
void Update()
{
spawnTime-= Time.deltaTime;
realTime += Time.deltaTime;
if (spawnTime < 0 && realTime<30f && realTime>5f)
{
GameObject go = Instantiate(enemy, new Vector3(Random.Range(-2.3f, 2.3f), 8f, 0), Quaternion.Euler(0, 0, 0)) as GameObject;
GameObject go1 = Instantiate(enemy, new Vector3(Random.Range(-2.3f, 2.3f), 8f, 0), Quaternion.Euler(0, 0, 0)) as GameObject;
spawnTime = defaultSpawnTime;
if (realTime > 30f)
{
realTime = 0f;
}
}
}
}
My game is 2D.
In the game, a meteorite rains every 2 seconds from above.
The player struggles with these.
But since the game is very tiring, I do not want meteorites to rain for 5 seconds every 30 seconds, so the player will have the opportunity to rest.
I also wanted to create a time variable and increase it in real-time.
And I tried the meteor shower to happen, provided the time was between 5 and 30.
If the time is greater than 30, I wanted to return it to 0 and loop it, but after 30 it continues to progress.
I don't know where I went wrong, can you help me?
Just move the if statment outside of first if. Because after realtime > 30 you condition " && realTime<30f && " not fulfilled
void Update()
{
spawnTime-= Time.deltaTime;
realTime += Time.deltaTime;
if (spawnTime < 0 && realTime<30f && realTime>5f)
{
GameObject go = Instantiate(enemy, new Vector3(Random.Range(-2.3f, 2.3f), 8f, 0), Quaternion.Euler(0, 0, 0)) as GameObject;
GameObject go1 = Instantiate(enemy, new Vector3(Random.Range(-2.3f, 2.3f), 8f, 0), Quaternion.Euler(0, 0, 0)) as GameObject;
spawnTime = defaultSpawnTime;
}
if (realTime > 30f)
{
realTime = 0f;
}
}
It gets hard to manage time like that after you add few timers. Try using Coroutines like:
void Start(){
StartMeteorShower(5f);
}
void StartMeteorShower(float time){
StartCoroutine(StartMeteorShowerDelayed(time);
}
IEnumerator StartMeteorShowerDelayed(float delay){
yield return new WaitForSeconds(delay);
StartCoroutine(MeteorShowerCoroutine());
}
IEnumerator MeteorShowerCoroutine(){
var startTime = Time.time;
var delay = new WaitForSeconds(1f);
do
{
SpawnMeteor();
yield return delay;
}
while(Time.time - startTime < _meteorShowerDuration);
//here you can queue next meteor shower
StartMeteorShower(30f);
}
I have a scene that is as follows:
I have the player object, which is a Z locked cube that I move around with a script, using various AddForce calls. The important method in there is this one:
public void SetDirections(Vector3 down)
{
down.Normalize();
this.down = down;
forward = Vector3.Cross(down, new Vector3(0, 0, 1));
}
Other code relating to rotation in the same script is this:
void Turning ()
{
// Irányitó gombok hatására a Taxi elforduljon 180fokot
Vector3 lookDirection = forward;
// balra forditás
if (inputh > 0)
{
faceLeft = false;
}
// jobbra forditás
if (inputh < 0)
{
faceLeft = true;
}
if (faceLeft)
{
lookDirection *= -1;
}
transform.LookAt(transform.position + lookDirection, new Vector3(0, 1, 0));
}
I have this bit on another object in the scene:
public class RotateGravity : MonoBehaviour
{
public GameObject Taxi;
public float MinLimit, MaxLimit;
private TaxiController tControl;
private Rigidbody tRigidbody;
private Transform tTransform;
void Start()
{
tControl = Taxi.GetComponent<TaxiController>();
tRigidbody = Taxi.GetComponent<Rigidbody>();
tTransform = Taxi.GetComponent<Transform>();
}
void OnTriggerStay()
{
Vector3 originalDown = tControl.Down;
Vector3 newDown = tTransform.position - gameObject.transform.position;
if (Vector3.SignedAngle(newDown, new Vector3(1, 0, 0), new Vector3(0, 0, 1)) > MinLimit &&
Vector3.SignedAngle(newDown, new Vector3(1, 0, 0), new Vector3(0, 0, 1)) < MaxLimit)
{
newDown.Normalize();
tControl.SetDirections(newDown);
float angle = Vector3.SignedAngle(originalDown, newDown, new Vector3(0, 0, 1));
tRigidbody.velocity = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1)) * tRigidbody.velocity;
}
Debug.Log("Stay: " + newDown);
}
void OnTriggerExit()
{
float angle = Vector3.Angle(tTransform.position - gameObject.transform.position, new Vector3(1, 0, 0));
Vector3 newDown;
float newAngle;
if (Mathf.Abs(angle - MinLimit) < Mathf.Abs(angle - MaxLimit))
{
newDown = Quaternion.AngleAxis(MinLimit, new Vector3(0, 0, -1)) * new Vector3(1, 0, 0);
newAngle = MinLimit;
}
else
{
newDown = Quaternion.AngleAxis(MaxLimit, new Vector3(0, 0, -1)) * new Vector3(1, 0, 0);
newAngle = MaxLimit;
}
Debug.Log("Exit: " + newDown + " " + newAngle);
tControl.SetDirections(newDown);
tRigidbody.velocity = Quaternion.AngleAxis(newAngle, new Vector3(0, 0, 1)) * tRigidbody.velocity;
}
}
Basically the idea is that the gravity direction changes as the player moves along the object, so just by moving right it would revolve around the object between the MinLimit and MaxLimit angles. Which it does. At the end I want to fix the direction to these limits and this is where a weird thing happens. In my example I have the MinLimit at 0 and the MaxLimit at 90. Meaning that the player enters horizontally from the left, and gravity changes from (0, -1, 0) to (1, 0, 0). Except, at the end the player object rotates 90 degrees around its forward vector.
Can somebody explain where I'm going wrong? I hate rotations in Unity :(
In the video below the red sphere is just an indicator under the player object to show better its facing.
https://www.youtube.com/watch?v=z4p9UQb7inA
Okay, I was not setting the up vector correctly in the Turning() method, it pointed in the positive Y direction, so when my forward direction ended up being the same it didn't know where to rotate the object on that axis. I'm dumb. I set the up vector to point to -1 * down, and boom, it worked.
In creating a level populator for my game, I created an array for my cube prefabs and made separate voids for each cube position so that each cube is randomised to a separate output from others (not putting separate voids just randomises the cubes to all be one colour at run time). I can make it work by creating separate voids for each object instance, but I want to know if it's possible to create a void array. Currently I get an error of unexpected [, ) in class/struct as well as primary constructor body not allowed.
Previous following of various tutorials only randomised the cubes to one colour at run time. I put the positions in an array and am not sure what to do with slot.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class testlevelscript : MonoBehaviour {
public GameObject[] blocks;
public int currentBlock;
void Start () {
//function instance
int[] slot = new[] {
1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < 10; i++) {
Instantiate (slot [i] ());
;
//slot[i]();
}
//position list
Vector3[] position = new[] {
new Vector3 (0, 0, 0),
new Vector3 (1, 0, 0),
new Vector3 (2, 0, 0),
new Vector3 (3, 0, 0),
new Vector3 (4, 0, 0),
new Vector3 (-1, 0, 0),
new Vector3 (-2, 0, 0),
new Vector3 (-3, 0, 0),
new Vector3 (-4, 0, 0),
new Vector3 (-5, 0, 0)};
Quaternion rotation = Quaternion.identity;
for (int i = 0; i < 10; i++) {
currentBlock = Random.Range (0, blocks.Length);
Instantiate (blocks [currentBlock], position [i], rotation);
}
}
void slot[i] () {
currentBlock = Random.Range (0, blocks.Length);
Instantiate (blocks [currentBlock], position[i], rotation);
}
}
Currently I have the script working manually, just want to see if it's possible to put it in some arrays to make it more efficient.
I am trying to get my Player prefabs leg and shoe to move "Forward" world space wise without my shoe on each leg rotating. I just want it pointing forward.
I have a player prefab. On the prefab I have a script, two gameobjects with a cylinder in each one acting as a "leg", and another two gameobject with a shoe model I made in each gameobject. the shoe gameobject is inside the leg gameobject. so for example it goes:
Player prefab
-> Right Leg Gameobject
-> Left Leg Gameobject
-> RightShoe Gameobject
-> Left Shoe Gameobject
and under each gameopbject is the respective models for the leg or shoe.
I have written code so that my player's legs "move"/"change rotation" to make it look like it's walking (I don't know any animation so this is the only way I know how). There is also code so that moving player is with AWSD and looking or rotating player is with the mouse, just like any typical FPS game, except my game in 3rd person.
My player's leg does move "forward" relative to world space so that is not an issue but hen I use the mouse to rotate or look in another direction (left or right), the players shoes also rotate left or right in place. At first I thought something was wrong with the shoes but I did not write any code to the shoes, I only wrote code for the legs. Since my legs were cylindrical, I did not notice the leg rotates too. I only found this out once I set my cylindrical legs to be more oblong or more egg shaped like.
is there a way I can make my shoes do the same "animation" as my leg but not make it rotate in place?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class PlayerController : NetworkBehaviour
{
public float speedH = 2.0f;
private float yaw = 0.0f;
public float WalkingTime; //timer for walking animation
public GameObject PlayerLeftLeg;
public GameObject PlayerRightLeg;
private float PlayerStatMenuTimer;
public GameObject PlayerStatsMenu;
public GameObject ThePlayer;
// Update is called once per frame
void Update () {
if (!isLocalPlayer)
{
return;
}
//keep track of time for player stat menu
//if not here than menua will show and hide like a thousand times when pressed once due to update reading code per frame
PlayerStatMenuTimer = PlayerStatMenuTimer + 1 * Time.deltaTime;
//moving player left right forward backward
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 50.0f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 50.0f;
transform.Translate(x, 0, z);
//rotating player or "Looking"
yaw += speedH * Input.GetAxis("Mouse X");
transform.eulerAngles = new Vector3(0.0f, yaw, 0.0f);
//if player is using WASD to move then do leg moving animation
//if not moving then set legs to be still and reset in standing position
//FYI: "transform.TransformVector(1,0,0)" was used instead of "Vector3.forward" was because
// vector3.forward is local space, so when i rotate player the sense of "forward" also changes, thus i needed
// a code that uses the world space, thus i used "transform.TransformVector(1,0,0)"
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D))
{
CmdWalk();
RpcWalk();
}
else
{
//if player not walking then reset
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
WalkingTime = 0;
}
//get hidden mouse pointer back and unlock
if (Input.GetKey(KeyCode.Escape))
{
Cursor.lockState = CursorLockMode.None;
}
//opens and closes stat menu
if (Input.GetKey(KeyCode.Return) && (PlayerStatMenuTimer>=1) && (PlayerStatsMenu.activeSelf==false))
{
Cursor.lockState = CursorLockMode.None;
PlayerStatsMenu.SetActive(true);
PlayerStatMenuTimer = 0;
//call the script "GetplayerStats" and call function "retrieceplayerstats"
var GetStats = GetComponent<GetPlayerStats>();
GetStats.RetrievePlayerStats();
}
else if (Input.GetKey(KeyCode.Return) && PlayerStatMenuTimer >= 1 && PlayerStatsMenu == true)
{
Cursor.lockState = CursorLockMode.Locked;
PlayerStatsMenu.SetActive(false);
PlayerStatMenuTimer = 0;
}
}
private void Awake()
{
//this code locks mouse onto center of window
//Screen.lockCursor = true;
Cursor.lockState = CursorLockMode.Locked;
}
//initiaztes when started up
void Start()
{
//calls script "SpawnItems" and function "RefreshItems" which will update the players items being shown
ThePlayer.GetComponent<SpawnItems>().RefreshItems();
}
//so COMMAND is for server to client
//it shows walking for local player
[Command]
void CmdWalk()
{
//timer
WalkingTime += Time.deltaTime;
//right leg stepping forward
if (WalkingTime > 0 && WalkingTime < .4)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector(1, 0, 0));
}
//left leg stepping forward
if (WalkingTime > .4 && WalkingTime < 1.2)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
}
//right leg stepping forward
if (WalkingTime > 1.2 && WalkingTime < 1.59)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
}
//resetting
if (WalkingTime > 1.6)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
WalkingTime = 0;
}
}
//so RPC is for Client to Server
//it shows walking for other client players
//https://stackoverflow.com/questions/53784897/unity-moving-player-leg-multiplayer
[ClientRpc]
void RpcWalk()
{
//timer
WalkingTime += Time.deltaTime;
//right leg stepping forward
if (WalkingTime > 0 && WalkingTime < .4)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * WalkingTime), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * WalkingTime), transform.TransformVector(1, 0, 0));
}
//left leg stepping forward
if (WalkingTime > .4 && WalkingTime < 1.2)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x + (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x - (60 * (WalkingTime - .8f)), transform.TransformVector(1, 0, 0));
}
//right leg stepping forward
if (WalkingTime > 1.2 && WalkingTime < 1.59)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(PlayerRightLeg.transform.rotation.x - (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(PlayerLeftLeg.transform.rotation.x + (60 * (WalkingTime - 1.6f)), transform.TransformVector(1, 0, 0));
}
//resetting
if (WalkingTime > 1.6)
{
PlayerRightLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
PlayerLeftLeg.transform.rotation = Quaternion.AngleAxis(0, Vector3.forward);
WalkingTime = 0;
}
}
}
I have included the entire script for my player controller, all you need to focus on is the CMDWALK or RPC WALK, they are both the same piece of code.
if anyone needs more info on the leg movement world space, take a look at this link, it is another question I asked Unity Moving Player Leg Multiplayer
The problem is you are mixing Euler angles with Quaternion values. This is never a good idea. While an Euler angles can be uniquely represent in Quaternion space, the other way round one Quaternion has multiple representations in Euler space. Therefore your direct access of rotation.x is not reliable (at least not for using it than in AngleAxis.
Additionally you are dealing with global rotation here. You should use local rotations instead to avoid the problems with nested rotated objects.
However in your case you should as already said simply use
transform.Rotate(60 * WalkingTime, 0, 0, Space.Self);
and for a reset simply
transform.localRotation = Quaternion.Identity;
Btw as I mentioned in my answer(the "Update" section) to your previous question don't forget to skip the ClientRpc if you are the server or the client who originally invoked the call to avoid duplicate movements. And don't call both, Cmd and Rpc at the same place this could lead to strange behaviours since the Rpc can only be called by the server. Call one method walk and from there go on with the Cmd which than Invokes the Rpc.
I created an empty game object and attached a line renderer component to it in the inspector and also set it's position size array to 2. The rest of the stuff was done in the following script for animating a line. When I run the code the values of the positions change whiles the width is always zero (my observation from the inspector), so the line does not appear. What's causing this and how can I solve it?
public class DrawLine : MonoBehaviour {
private LineRenderer lineRenderer;
private float counter;
private float dist;
public float lineDrawSpeed;
// Use this for initialization
void Start () {
lineRenderer = GetComponent<LineRenderer> ();
lineRenderer.startWidth = 0.25f;
lineRenderer.endWidth = 0.25f;
lineRenderer.SetPosition (0, new Vector3 (0, 0, 0));
dist = Vector3.Distance (new Vector3 (0, 0, 0), new Vector3 (1.5f, 0, 0));
}
// Update is called once per frame
void Update () {
if (counter < dist) {
counter += 0.1f / lineDrawSpeed;
float x = Mathf.Lerp (0, dist, counter);
Vector3 pointA = new Vector3 (0, 0, 0);
Vector3 pointB = new Vector3 (1.5f, 0, 0);
Vector3 pointAlongLine = x * Vector3.Normalize (pointB - pointA) + pointA;
lineRenderer.SetPosition (1, pointAlongLine);
}
}
}
You should check if your float x = Mathf.Lerp (0, dist, counter); is ever 0 because if yes then Vector3 pointAlongLine wil be 0 also so you will draw line from 0 to 0.
Next check your LineRenderer.widthMultiplier if it's 0 your line won't be drawn also.
Also I gave a try to your code and this is the result:
So I'd like you to explain more what do you want to acheive.