How to animate a mesh to make it resemble a waving flag? - c#

I'm trying to animate a waving flag as shown in this video: https://www.youtube.com/watch?v=rWirey_oNPY&t=7s, but I can't seem to do it correctly. An initial mesh has already been created : My goal is to move each column of VerticeArray[,] (2D array containing the Vector3() of each vertices) in a sin function so that the mesh resembles a waving flag. GenerateVertices() transforms a 2D array to a 1D array, mg.nRows represents the number of rows that the mesh contains (in this case 5), and mg.Columns the number of columns that it contains (in this case 3). Your help is very appreciated.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class PlaneMeshDeformComponent : MonoBehaviour
{
[SerializeField] public float amplitude;
[SerializeField] private bool activate;
private Mesh m;
private Vector3[] verticesCopy;
private Vector3[,] verticeArray;
private PlaneMeshGeneratorComponent mg;
private float step = 0;
private float previousStep = 0;
private void Start()
{
mg = GetComponent<PlaneMeshGeneratorComponent>();
m = GetComponent<MeshFilter>().mesh;
verticesCopy = m.vertices;
for (int i = 0; i < verticesCopy.Length; ++i)
{
verticesCopy[i] += new Vector3(0, 0, amplitude * Mathf.Sin((float)(verticesCopy[i].x * (2*Math.PI/verticesCopy[^1].x))));
}
//4.
m.vertices = verticesCopy;
//5.
m.RecalculateNormals();
verticeArray = GenerateArray(m.vertices);
/*for (int i = 0; i <= mg.nColumns; i++)
{
for (int k = 0; k <= mg.nRows; k++)
{
Debug.Log(verticeArray[k,i]);
}
}*/
}
private void Update()
{
step += Time.deltaTime;
for (int i = 0; i <= mg.nColumns; i++)
{
for (int k = 0; k <= mg.nRows; k++)
{
verticeArray[k, i] = new Vector3(verticeArray[k,i].x, verticeArray[k,i].y, verticeArray[k,i].z+amplitude*(Mathf.Sin(step)-Mathf.Sin(previousStep)));
m.vertices = mg.GenerateVertices(verticeArray);
Debug.Log($"step is {step}, previous is {previousStep}");
}
}
previousStep = step;
}
private Vector3[,] GenerateArray(Vector3[] verticesList)
{
Vector3[,] vArray= new Vector3[mg.nRows+1, mg.nColumns+1];
for (int i = 0; i <= mg.nRows; i++)
{
for (int k = 0; k <= mg.nColumns; k++)
{
vArray[i,k] = verticesList[i * (mg.nColumns+1) + k];
}
}
return vArray;
}
}

Related

I am not able to successfully move my background with the script below

The script below is intended to move the background with the character. However, the background does not move at all when using this code and I suspect the problem may be somewhere in the LateUpdate function as once that is changed to update, the background continuously moves on its own, but not with the player.
public class ParallaxController : MonoBehaviour
{
Transform cam; // Main Camera
Vector3 camStartPos;
Vector2 distance;
GameObject[] backgrounds;
Material[] mat;
float[] backSpeed;
float farthestBack;
[Range(0f,0.05f)]
public float parallaxSpeed;
void Start()
{
cam = Camera.main.transform;
camStartPos = cam.position;
int backCount = transform.childCount;
mat = new Material[backCount];
backSpeed = new float[backCount];
backgrounds = new GameObject[backCount];
for (int i = 0; i < backCount; i++)
{
backgrounds[i] = transform.GetChild(i).gameObject;
mat[i] = backgrounds[i].GetComponent<Renderer>().material;
}
BackSpeedCalculate(backCount);
}
void BackSpeedCalculate(int backCount)
{
for (int i = 0; i < backCount; i++)
{
if ((backgrounds[i].transform.position.z - cam.position.z) > farthestBack)
{
farthestBack = backgrounds[i].transform.position.z - cam.position.z;
}
}
for (int i = 0; i < backCount; i++)
{
backSpeed[i] = 1 - (backgrounds[i].transform.position.z - cam.position.z) / farthestBack;
}
}
void LateUpdate()
{
distance = cam.position - camStartPos;
transform.position = new Vector3(cam.position.x, transform.position.y, 0);
for (int i = 0; i < backgrounds.Length; i++)
{
float speedX = backSpeed[i] * parallaxSpeed;
float speedY = speedX / 2; // if you close Y movement , set to 0
mat[i].SetTextureOffset("_MainTex", new Vector2(distance.x*speedX, distance.y*speedY));
Debug.Log("for loop works!");
}
}
}

Can't move Instatiated Object from queue, changes transform of prefab instead

I'm trying to make a "Mania" style game(like guitar hero). But i can't seem to get the Movement of the "notes" to work, I keep the notes in a queue and I dequeue the last note and change it's position to the top again. But for some reason it doesen't work with my "goodcubes". only the normal ones
The problem seems to be that the instead of moving the "goodCube" to the correct position it instead changes the transform of the prefab.
All "notes" are referred to as "Cubes" in script
for (int i = 0; i < backlog; i++)//how many rows to spawn
{
goodCubes.Enqueue(Instantiate(goodcube));
for (int j = 0; j < columns - 1; j++)
{
badCubes.Enqueue(Instantiate(cube));
}
}
//I check the player input and if it corresponds with a note in the correct row
//I have tested so both true and false option gets called
if (i == position)
{
GameObject good = goodCubes.Dequeue();
good.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
goodCubes.Enqueue(goodcube);
}
else
{
GameObject badCube = badCubes.Dequeue();
badCube.transform.position = spawnPoint;`enter code here`
spawnPoint += new Vector2(1 * rowOffset, 0);
badCubes.Enqueue(badCube);
}
The full script
public int columus;
public GameObject cube;
public GameObject goodcube;
public event Action moveCubes;
[SerializeField] private int score = 0;
[SerializeField] private float rowOffset = 1;
[SerializeField] private float heightDifference = 1;
[SerializeField] private int backlog = 4;
private float SpawnHeight;
Queue<int> positions = new Queue<int>();
Queue<GameObject> badCubes = new Queue<GameObject>();
Queue<GameObject> goodCubes = new Queue<GameObject>();
private void Start()
{
for (int i = 0; i < backlog; i++)
{
goodCubes.Enqueue(Instantiate(goodcube));
for (int j = 0; j < columus - 1; j++)
{
badCubes.Enqueue(Instantiate(cube));
}
}
for (int i = 0; i < backlog; i++)
{
positions.Enqueue(SpawnRow(i * heightDifference));
}
}
int SpawnRow(float y)
{
int position = UnityEngine.Random.Range(0, columus);
Vector2 spawnPoint = new Vector2(-columus * rowOffset / 2f, y);
for (int i = 0; i < columus; i++)
{
if (i == position)
{
GameObject goodCube = goodCubes.Dequeue();
goodCube.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
goodCubes.Enqueue(goodcube);
}
else
{
GameObject badCube = badCubes.Dequeue();
badCube.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
badCubes.Enqueue(badCube);
}
}
return position;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.D))
{
UpdateScore(0);
}
else if (Input.GetKeyDown(KeyCode.F))
{
UpdateScore(1);
}
else if (Input.GetKeyDown(KeyCode.J))
{
UpdateScore(2);
}
else if (Input.GetKeyDown(KeyCode.K))
{
UpdateScore(3);
}
} //inputcheck
private void UpdateScore(int input)
{
if (positions.Dequeue() == input)
{
moveCubes?.Invoke();
positions.Enqueue(SpawnRow(backlog * heightDifference + 1 * heightDifference));
score++;
}
else
{
moveCubes?.Invoke();
positions.Enqueue(SpawnRow(backlog * heightDifference + 1 * heightDifference));
score--;
}
}
I truly believe your issue is a typo in your code. That usually happens when you have variables with the same name. Your issue is that you are enqueuing the prefab goodcube and not the goodCube object:
GameObject goodCube = goodCubes.Dequeue();
goodCube.transform.position = spawnPoint;
spawnPoint += new Vector2(1 * rowOffset, 0);
//******HERE YOU ARE ENQUEUEING THE PREFAB goodcube AND NOT goodCube as your variable name suggests two lines above this line*****
goodCubes.Enqueue(goodCube);//INSTEAD OF goodCubes.Enqueue(goodcube);

How to take 3 floats and put them in a transform.postion which is a vector3?

While I was coding for a tower builder game(like this one), I needed a way to spawn the tower, so I used Instantiate and for the transform I created a variable called "place" and I tried using the for loop variables for it but it did not work.
Here is my script:
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
public class spawner : MonoBehaviour
{
public float3 startingLocation;
Transform place;
public void SpwanTower(float xx, float yy, float zz, GameObject Brick)
{
for (int i = 0; i < yy; i++)
{
for (int e = 0; e < xx; e++)
{
for (int o = 0; o < zz; o++)
{
Instantiate(Brick,place);
}
}
}
}
}
I think you want something on the line of:
Instantiate(Brick, new Vector3(e, i, o), Quaternion.identity);
because you are not using e, i and o variables.
try this
public float3 startingLocation;
Transform place;
public void SpwanTower(float xx, float yy, float zz, GameObject Brick)
{
Vector3 currPos = new Vector3(
startingLocation.x,
startingLocation.y,
startingLocation.z
);
for (int i = 0; i < yy; i++)
{
for (int e = 0; e < xx; e++)
{
for (int o = 0; o < zz; o++)
{
//you can change the plus sign to determine to what direction the tower will be built
currPos.x = startingLocation.x + e;
currPos.y = startingLocation.y + i;
currPos.z = startingLocation.z + o;
Instantiate(Brick, currPos, Quaternion.identity);
}
}
}
}
OBS: instead of doing new Vector3(e, i, o),
its better to change the x, y, z values of the currPos, since that will executed several times
hope it works.

How can I add more lights if twoSides flag is true?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LightsEffect : MonoBehaviour
{
public List<UnityEngine.GameObject> waypoints;
public int howmanylight = 5;
public bool changeLightsDirection = false;
public bool twoSides = false;
public float delay = 0.1f;
private List<UnityEngine.GameObject> objects;
private Renderer[] renderers;
private int greenIndex = 0;
private float lastChangeTime;
private void Start()
{
objects = new List<UnityEngine.GameObject>();
if (howmanylight > 0)
{
UnityEngine.GameObject go1 = UnityEngine.GameObject.CreatePrimitive(PrimitiveType.Sphere);
duplicateObject(go1, howmanylight);
LightsEffects();
}
}
private void Update()
{
LightsEffectCore();
}
public void duplicateObject(UnityEngine.GameObject original, int howmany)
{
if (twoSides == true)
howmany = howmany * 2;
howmany++;
for (int i = 0; i < waypoints.Count - 1; i++)
{
for (int j = 1; j < howmany; j++)
{
Vector3 position = waypoints[i].transform.position + j * (waypoints[i + 1].transform.position - waypoints[i].transform.position) / howmany;
UnityEngine.GameObject go = Instantiate(original, new Vector3(position.x, 0.05f, position.z), Quaternion.identity);
go.transform.localScale = new Vector3(0.3f, 0.1f, 0.3f);
objects.Add(go);
}
}
}
private void LightsEffects()
{
renderers = new Renderer[objects.Count];
for (int i = 0; i < renderers.Length; i++)
{
renderers[i] = objects[i].GetComponent<Renderer>();
renderers[i].material.color = Color.red;
}
// Set green color to the first one
greenIndex = 0;
renderers[greenIndex].material.color = Color.green;
}
private void LightsEffectCore()
{
// Change color each `delay` seconds
if (Time.time > lastChangeTime + delay)
{
lastChangeTime = Time.time;
// Set color of the last renderer to red
// and the color of the current one to green
renderers[greenIndex].material.color = Color.red;
if (changeLightsDirection == true)
{
Array.Reverse(renderers);
changeLightsDirection = false;
}
greenIndex = (greenIndex + 1) % renderers.Length;
renderers[greenIndex].material.color = Color.green;
}
}
}
Inside the method duplicateObject I'm checking if the flag twoSides is true and then double by twice the amount of lights:
public void duplicateObject(UnityEngine.GameObject original, int howmany)
{
if (twoSides == true)
howmany = howmany * 2;
howmany++;
for (int i = 0; i < waypoints.Count - 1; i++)
{
for (int j = 1; j < howmany; j++)
{
Vector3 position = waypoints[i].transform.position + j * (waypoints[i + 1].transform.position - waypoints[i].transform.position) / howmany;
UnityEngine.GameObject go = Instantiate(original, new Vector3(position.x, 0.05f, position.z), Quaternion.identity);
go.transform.localScale = new Vector3(0.3f, 0.1f, 0.3f);
objects.Add(go);
}
}
}
This lines:
if (twoSides == true)
howmany = howmany * 2;
But this will add just more 5 lights between the waypoints like it show in the screenshot.
And I want it to add more 5 lights but to create two lines between the waypoints of lights line by line.
Somehow to change the new 5 lights position so it will be near/next the first 5 lights. And then to align the lines of lights so they will be equal between the waypoints.
Two lines and two sides I mean something like this:
But they should be equal between the waypoints like in the first screenshot.
What I tried is this:
Changed the duplicateObject method to:
public void duplicateObject(UnityEngine.GameObject original, int howmany)
{
GameObject go = new GameObject();
if (twoSides == true)
howmany = howmany * 2;
howmany++;
for (int i = 0; i < waypoints.Count - 1; i++)
{
for (int j = 1; j < howmany; j++)
{
Vector3 position = waypoints[i].transform.position + j * (waypoints[i + 1].transform.position - waypoints[i].transform.position) / howmany;
if (j > 5)
{
go = Instantiate(original, new Vector3(position.x + 1, 0.05f, position.z), Quaternion.identity);
}
else
{
go = Instantiate(original, new Vector3(position.x, 0.05f, position.z), Quaternion.identity);
}
go.transform.localScale = new Vector3(0.3f, 0.1f, 0.3f);
objects.Add(go);
}
}
}
But the result is not what I wanted:
Now the problem is that the lights the gaps between them is not equal between the two waypoints (cubes) and also the new 5 lights are two far from the waypoints.
Both lights each 5 lights should be with equal gaps and side by side between the waypoints. Like a landing lights for aircraft between the two waypoints.

Unity 5 Can't Get Component (Trying to pull from another class)

Hey guys I'm making a Terraria-like game, I've been creating the biomes but have been having trouble rendering the chunks. I've put the second code in a "GameMaster" gameobject in the game. And used Gameobject Chunk in the second code to attach a gameobject with the first code. For some reason my GetComponent<>().width; doesn't recognize the ChunkGenerator class. Therefore giving me errors. Anything helps. Thanks. I've attached the two codes below.
Here's the first code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChunkGenerator : MonoBehaviour {
public GameObject DirtTile;
public GameObject StoneTile;
public GameObject GrassTile;
public GameObject SandTile;
public int heightAddition;
public int width;
public float heightMultiplier;
float worldSeed;
float playerSpawnBiome;
public float smoothness;
public float mountSmooth;
void Start () {
// playerSpawnBiome = Random.Range (-5f, 10f);
// if (playerSpawnBiome > 0f) {
// GenerateMountainBiome ();
// } else if ((playerSpawnBiome > 0f) && (playerSpawnBiome <= 5f)) {
GeneratePlainsBiome ();
// } else {
// GenerateSandBiome ();
// }
}
public void GeneratePlainsBiome() {
worldSeed = Random.Range (-10000f, 10000f);
for (int i = 0; i < width; i++)
{
int h = Mathf.RoundToInt(Mathf.PerlinNoise (worldSeed, (i + transform.position.x / smoothness) * heightMultiplier) + heightAddition);
for (int j = 0; j < h; j++) {
GameObject selectedTile;
if (j < h - 3) {
selectedTile = StoneTile;
} else if (j < h - 1) {
selectedTile = DirtTile;
} else {
selectedTile = GrassTile;
}
GameObject newTile = Instantiate (selectedTile, Vector3.zero, Quaternion.identity) as GameObject;
newTile.transform.parent = this.gameObject.transform;
newTile.transform.localPosition = new Vector3 (i, j);
}
}
}
public void GenerateSandBiome() {
worldSeed = Random.Range (-10000f, 10000f);
for (int i = 0; i < width; i++)
{
int h = Mathf.RoundToInt(Mathf.PerlinNoise (worldSeed, (i / smoothness) * heightMultiplier) + heightAddition);
for (int j = 0; j < h; j++) {
GameObject selectedTile;
if (j < h - 3) {
selectedTile = StoneTile;
} else if (j < h - 1) {
selectedTile = SandTile;
} else {
selectedTile = SandTile;
}
Instantiate (selectedTile, new Vector3(i, j), Quaternion.identity);
}
}
}
public void GenerateMountainBiome() {
worldSeed = Random.Range (-10000f, 10000f);
for (int i = 0; i < width; i++)
{
int h = Mathf.RoundToInt(Mathf.PerlinNoise (worldSeed, (i / 3f) * mountSmooth) * heightMultiplier) + heightAddition;
for (int j = 0; j < h; j++) {
GameObject selectedTile;
if (j < h - 3) {
selectedTile = StoneTile;
} else if (j < h - 1) {
selectedTile = DirtTile;
} else {
selectedTile = GrassTile;
}
Instantiate (selectedTile, new Vector3(i, j), Quaternion.identity);
}
}
}
}
Here's the second Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChunkGenerators : MonoBehaviour {
public GameObject chunk;
int chunkWidth;
public int numChunks;
float seed;
void Start() {
chunkWidth = chunk.GetComponent<ChunkGenerator> ().width;
seed = Random.Range (-1000000f, 1000000f);
Generate ();
}
public void Generate() {
int lastX = -chunkWidth;
for (int i = 0; i < numChunks; i++) {
GameObject newChunk = Instantiate (chunk, new Vector3 (lastX + chunkWidth, 0f), Quaternion.identity) as GameObject;
newChunk.GetComponent<ChunkGenerator> ().seed = seed;
lastX += chunkWidth;
}
}
}
Its because you are referencing the wrong script. You're mistakingly referencing ChunkGenerator instead of ChunkGenerators.
Change:
newChunk.GetComponent<ChunkGenerator> ().seed = seed;
to
newChunk.GetComponent<ChunkGenerators> ().seed = seed;

Categories