How to instantiate object class that contains GameObject? [duplicate] - c#

This question already has answers here:
Declaring a new instance of a class in C#
(2 answers)
Closed 2 years ago.
I am attempting to instantiate a large number of "particles" using a C# script in Unity. I have created a particle class that contains the creation of a corresponding GameObject. The GameObject within each particle instance is a sphere. When attempting to instantiate a new particle (Particle p = new Particle(...)) I get a Unity warning that the 'new' keyword should not be used.
"You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
UnityEngine.MonoBehaviour:.ctor()"
What is the proper way to instantiate a number of instances of my particle class (each containing a singular sphere GameObject)?
Particle Class:
public class Particle : MonoBehaviour {
Vector3 position = new Vector3();
Vector3 velocity = new Vector3();
Vector3 force = new Vector3();
Vector3 gravity = new Vector3(0,-9.81f,0);
int age;
int maxAge;
int mass;
GameObject gameObj = new GameObject();
public Particle(Vector3 position, Vector3 velocity)
{
this.position = position;
this.velocity = velocity;
this.force = Vector3.zero;
age = 0;
maxAge = 250;
}
// Use this for initialization
void Start () {
gameObj = GameObject.CreatePrimitive (PrimitiveType.Sphere);
//gameObj.transform.localScale (1, 1, 1);
gameObj.transform.position = position;
}
// FixedUopdate is called at a fixed rate - 50fps
void FixedUpdate () {
}
// Update is called once per frame
public void Update () {
velocity += gravity * Time.deltaTime;
//transform.position += velocity * Time.deltaTime;
gameObj.transform.position = velocity * Time.deltaTime;
Debug.Log ("Velocity: " + velocity);
//this.position = this.position + (this.velocity * Time.deltaTime);
//gameObj.transform.position
}
}
CustomParticleSystem Class:
public class CustomParticleSystem : MonoBehaviour {
Vector3 initPos = new Vector3(0, 15, 0);
Vector3 initVel = Vector3.zero;
private Particle p;
ArrayList Particles = new ArrayList();
// Use this for initialization
void Start () {
Particle p = new Particle (initPos, initVel);
Particles.Add (p);
}
// Update is called once per frame
void Update () {
}
}
Any help is greatly appreciated!

Your code looks fine other than you may have accidentally typed the declaration wrong for gameObj
Change GameObject gameObj = new GameObject(); to just GameObject gameObj = null; in your Particle class.
The error specifically mentions that you cannot do what you did and in your Start() you are setting it like it mentioned.
EDIT: Looking at Particle, it inherits MonoBehaviour. You need to have gameObject create the instance for you using gameObject.AddComponent<Particle>();
http://docs.unity3d.com/ScriptReference/GameObject.AddComponent.html
gameObject is defined on MonoBehaviour so you should have access to it already.

Related

Instantiated Prefab not moving as expected

I'm having an issue instantiating Prefabs in Unity.
I'm working on a game where you have enemies moving towards you and you have to kill them. My original enemy game object moved towards the player with little to no problem, but the instantiations of that object wouldn't move.
To make matters more confusing, when I copied the game object and added it to the scene without instantiation, both game objects would move towards the player just fine.
Enemy script:
public class EnemieController : MonoBehaviour
{
[SerializeField]
float moveSpeed = 1;
[SerializeField]
private Rigidbody2D rb;
public Transform player;
public float health = 50;
void Start()
{
rb = GetComponent<Rigidbody2D>();
Debug.Log(player);
}
// Update is called once per frame
void Update()
{
MoveTowardsPlayer();
}
void MoveTowardsPlayer()
{
Vector3 mousepos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = (player.position - transform.position).normalized;
rb.velocity = new Vector2(direction.x * moveSpeed, direction.y * (moveSpeed * 1));
}
}
Instantiation Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using System;
[System.Serializable]
public class GameManagement : MonoBehaviour
{
public GameObject circleEnemie;
public Transform player;
[SerializeField]
float moveSpeed = 1;
// Start is called before the first frame update
void Start()
{
//Get random position to spawn ball
Vector3 screenPosition = Camera.main.ScreenToWorldPoint(new Vector3(Random.Range(0, Screen.width), Random.Range(0, Screen.height), Camera.main.farClipPlane / 2));
GameObject enemie = Instantiate(circleEnemie, screenPosition, Quaternion.identity) as GameObject;
enemie.name = "enemiecircle";
enemie.tag = "Enemie";
}
// Update is called once per frame
void Update()
{
}
}
And if wanted, here are the enemies inspector specifications
Inspector Specifications
Sorry about the link, my reputation points are yet to reach 10 so I can't post images directly.
My guess would be that the Player referenced in your enemy prefab is a prefab itself that never moves.
You should make the prefab field itself of type EnemyController. This makes sure you only can reference a prefab here that actually has an EnemyController attached.
Then after Instantiate you can pass in the player reference of the GameManagement script like
public class GameManagement : MonoBehaviour
{
// Give this field the correct type
public EnemyController circleEnemie;
public Transform player;
[SerializeField]
float moveSpeed = 1;
// Start is called before the first frame update
void Start()
{
//Get random position to spawn ball
Vector3 screenPosition = Camera.main.ScreenToWorldPoint(new Vector3(Random.Range(0, Screen.width), Random.Range(0, Screen.height), Camera.main.farClipPlane / 2));
// Instantiate returns the same type as the given prefab
EnemyController enemy = Instantiate(circleEnemie, screenPosition, Quaternion.identity);
enemy.name = "enemiecircle";
enemy.gameObject.tag = "Enemie";
// Now pass in the player reference
enemy.player = player;
}
// NOTE: When not needed better remove Unity message methods
// It would just cause overhead
//void Update()
//{
//}
}
Sidenote: In your EnemyController in MoveTowardsPlayer what do you need this for?
Vector3 mousepos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Then whenever dealing with Rigidbody do the things in FixedUpdate otherwise it might break the physics and collision detection!
Then also don't use the Transform values but again the Rigidbody
private void FixedUpdate ()
{
MoveTowardsPlayer();
}
private void MoveTowardsPlayer ()
{
var direction = ((Vector2)(player.position - rb.position)). normalized;
rb.velocity = direction * moveSpeed;
}

Spawned Units always move to same target regardless of setting alternate points

I am new to unity and i am trying to create a new game.
using UnityEngine;
using System.Collections;
public class Enemyblue1script : MonoBehaviour {
// Use this for initialization
public float speed; // speed variable
public float RotSpeed = 90f;
public GameObject RocketGO; // Reference to our main character Rocket
void Start ()
{}
void Update()
{
Vector2 Pos = new Vector2 (-10, 5);
gameObject.transform.position = Vector3.MoveTowards (gameObject.transform.position, Pos, speed * Time.deltaTime);
Invoke ("MoveFace", 2f);
}
void MoveFace()
{
if( RocketGO == null)
{
GameObject go = GameObject.FindGameObjectWithTag("Rocket");
if(go != null){
RocketGO = go ;}
}
if( RocketGO == null)
return;
Vector3 dir = RocketGO.transform.position - gameObject.transform.position;
dir.Normalize();
float zAngle = Mathf.Atan2(dir.x , dir.y) * Mathf.Rad2Deg + 360;
Quaternion desiredRot = Quaternion.Euler(0 ,0,-zAngle);
gameObject.transform.rotation = Quaternion.RotateTowards(gameObject.transform.rotation , desiredRot , RotSpeed * Time.deltaTime);
}
}
This is my script for Moving Enemy towards some point (using MoveTowards funtion) and rotating enemy to Players direction. And i have one more script that is for Spawning these enemeies (Two Enemies at a time ) Script is
using UnityEngine;
using System.Collections;
public class Enemy1Spawner : MonoBehaviour {
//our meteorite prefab
public GameObject Enemy1blue;
public float speed;
public GameObject p1;
public GameObject p2;
// Use this for initialization
void Start ()
{}
// Update is called once per frame
void Update ()
{}
void SpawnEnemy1blue()
{
//bottom left point of screen
//Vector2 min = Camera.main.ViewportToWorldPoint (new Vector2 (0, 0));
//top right point of screen
//Vector2 max = Camera.main.ViewportToWorldPoint (new Vector2 (1, 1));
GameObject Enemy1ablue = (GameObject)Instantiate (Enemy1blue);
GameObject Enemy2ablue = (GameObject)Instantiate (Enemy1blue);
Enemy1ablue.transform.position = new Vector2 (-11,9);
Enemy2ablue.transform.position = new Vector2 (11,9);
}
public void startEnemy1blueSpawner()
{
Debug.Log ("Invoked Spawning Blue Enemy");
InvokeRepeating ("SpawnEnemy1blue",5f,30f);
}
//function to stop spawning when game over
public void StopEnemy1blueSpawning()
{
CancelInvoke ("SpawnEnemy1blue");
}
}
So now while Spawning enemies! my enemies are moving towards only one point i.e Vector2 Pos = new Vector2 (-10, 5); which I have defined in Updat() method of Enemyblue1script, and i want to spawn two enemies at a different positions one at Vector2 Pos = new Vector2 (-10, 5) (to the left side); and one at Vector2 Pos = new Vector2 (10, 5) (to the right side);
By using these two scripts i am able to spawn two enemies at a time, but they both move to same point, which is what i do not want to happen. I have tried stuff like in ENEMY1SPAWNER script > SpawnEnemy1blue() function i have also created two points using vector2 and i called two Movetowards functions there for two different enemies but is not working they are not moving.
Vector2 Pos1 = new Vector2 (-10, 5);
Vector2 Pos2 = new Vector2 (10, 5);
GameObject Enemy1ablue = (GameObject)Instantiate (Enemy1blue);
GameObject Enemy2ablue = (GameObject)Instantiate (Enemy1blue);
Enemy1ablue.transform.position = new Vector2 (-11,9);
Enemy2ablue.transform.position = new Vector2 (11,9);
Enemy1ablue.transform.position = Vector3.MoveTowards (Enemy1ablue.transform.position, Pos1, speed * Time.deltaTime);
Enemy2ablue.transform.position = Vector3.MoveTowards (Enemy2ablue.transform.position, Pos2, speed * Time.deltaTime);
It's hard to tell exactly where you put this line:
Enemy1ablue.transform.position = Vector3.MoveTowards(
Enemy1ablue.transform.position, Pos1, speed * Time.deltaTime);
But if it's just in SpawnEnemy1blue() then it will only happen once, so the enemy will move a little closer to the target then stop.
I suggest organizing the code a little differently: add a Vector2 target field to Enemyblue1script, set it when you initialize a new enemy, and move towards it in Enemyblue1script.Update. Instead of creating and using Pos, use target.

Creating a parameter from a player object

This might seem like a stupid question but I am having trouble passing a parameter into a constructor in one of my classes. The object I have created is a player object and I am trying to get its position in my enemy class. The reason why I am trying to do this is because I want my enemies to follow the player around the screen. I am using c# in psm to create this program. Any assistance is greatly needed.
This is my enemy class.
public class SmartEnemy:Enemy
{
private Player player;
private Vector3 vel, pos;
private static Random gen= new Random();
public SmartEnemy (GraphicsContext g, Texture2D t, Vector3 p, float pwr, Player pop) : base(g,t,p,pwr)
{
pos = p;
player = pop;
vel = new Vector3 (0, 0, 0);
sprite.Rotation = 0;
sprite.Center.X = 0.5f;
sprite.Center.Y = 0.5f;
}
public override void Update()
{
Vector3 playerPos= player.Pos;
double angle=Math.Atan2(playerPos.Y-sprite.Position.Y,playerPos.X- sprite.Position.X);
Vector3 vel=new Vector3((float)Math.Cos(angle),(float)Math.Sin(angle),0);
sprite.Position+=vel;
}
public override void Render()
{
sprite.Render();
}
}
//
}
This is my code in my Appmain that creates an enemy.
pieces.Add (new SmartEnemy(graphics, eTex, new Vector3(gen.Next (200,900), gen.Next (200,900),0),.5f));
Your SmartEnemy constructor expects a Player object, yet you're not supplying one in your code:
SmartEnemy(graphics, eTex, new Vector3(gen.Next (200,900), gen.Next (200,900),0),.5f));
Create a player object and send in:
Player p1 = new Player();
pieces.Add( new SmartEnemy(graphics, eTex, new Vector3(gen.Next (200,900), gen.Next (200,900),0),.5f, p1) );

Camera Smooth Follow 2D from UnityScript to C# using Unity3D

I am making a script to be used on the Main Camera object of Unity3D so the camera follows the character in a 2D platformer world.
I tried to translate this from a UnityScript script to c#, I am getting an error in line 26: "Cannot modify a value type return value of 'UnityEngine.Transform.position'. Consider storing the value in a temporary variable."
Original UnityScript Version
var cameraTarget : GameObject;
var player : GameObject;
var smoothTime : float = 0,1;
var cameraFollowX : boolean = true;
var cameraFollowY : boolean = true;
var cameraFollowHeight : boolean = false;
var cameraHeight : float = 2.5;
var velocity : Vector2;
private var thisTransform : Transform;
function Start ()
{
thisTransform = transform;
}
function Update ()
{
if (cameraFollowX)
{
thisTransform.position.x = Mathf.SmoothDamp (thisTransform.position.x, cameraTarget.transform.position.x, velocity.x, smoothTime);
}
if (cameraFollowY)
{
thisTransform.position.y = Mathf.SmoothDamp (thisTransform.position.y, cameraTarget.transform.position.y, velocity.y, smoothTime);
}
if (!cameraFollowX & cameraFollowHeight)
{
camera.transform.position.y = cameraHeight;
}
}
My C# Version
using UnityEngine;
using System.Collections;
public class CameraSmoothFollow : MonoBehaviour {
public GameObject cameraTarget; // object to look at or follow
public GameObject player; // player object for moving
public float smoothTime = 0.1f; // time for dampen
public bool cameraFollowX = true; // camera follows on horizontal
public bool cameraFollowY = true; // camera follows on vertical
public bool cameraFollowHeight = true; // camera follow CameraTarget object height
public float cameraHeight = 2.5f; // height of camera adjustable
public Vector2 velocity; // speed of camera movement
private Transform thisTransform; // camera Transform
// Use this for initialization
void Start () {
thisTransform = transform;
}
// Update is called once per frame
void Update () {
if (cameraFollowX){
thisTransform.position.x = Mathf.SmoothDamp (thisTransform.position.x, cameraTarget.transform.position.x, ref velocity.x, smoothTime); // Here i get the error
}
if (cameraFollowY) {
// to do
}
if (!cameraFollowX & cameraFollowHeight) {
// to do
}
}
}
Any help will be appreciated.
This error occurs because Transform.position is of a value type (probably a struct). This means that when you access the X property of position, you are accessing a COPY and NOT the real thing. To assign to the position property, you will need to create a new Vector3 and assign it to the position property. Your code will look something like this:
thisTransform.position = new Vector3 (Mathf.SmoothDamp (thisTransform.position.x, cameraTarget.transform.position.x, ref velocity.x, smoothTime), thisTransform.position.y, thisTransform.position.z);
or perhaps more cleaner:
float tempX = new Vector3 (Mathf.SmoothDamp (thisTransform.position.x, cameraTarget.transform.position.x, ref velocity.x, smoothTime);
thisTransform.position = new Vector3 (tempX, thisTransform.position.y, thisTransform.position.z);
You can also use this smooth follow script for both 2d and 3d camera and its very simple.
using UnityEngine;
using System.Collections;
public class FollowCamera : MonoBehaviour {
public float interpVelocity;
public float minDistance;
public float followDistance;
public GameObject target;
public Vector3 offset;
Vector3 targetPos;
// Use this for initialization
void Start () {
targetPos = transform.position;
}
// Update is called once per frame
void FixedUpdate () {
if (target)
{
Vector3 posNoZ = transform.position;
posNoZ.z = target.transform.position.z;
Vector3 targetDirection = (target.transform.position - posNoZ);
interpVelocity = targetDirection.magnitude * 5f;
targetPos = transform.position + (targetDirection.normalized * interpVelocity * Time.deltaTime);
transform.position = Vector3.Lerp( transform.position, targetPos + offset, 0.25f);
}
}
}
got it from github here
https://gist.github.com/unity3diy/5aa0b098cb06b3ccbe47
Use FixedUpdate()
If it's Update() the camera jerking will occur.

Wont allow me to create more than 1 LineRenderer

I am attempting to create LineRenderers at runtime(when the user presses a button).
My Problem: I can never create more than one LineRenderer. When I go to created the 2nd one, the LineRenderer object is always NULL.
What am I doing wrong? Can you provide advice on what I need to do to create more than one LineRenderer?
public class AppInit : MonoBehaviour {
public Vector3[] TEST_VERTICES;
public const int SPEED = 5;
public List<LineRenderer> lines;
// Use this for initialization
void Start () {
TEST_VERTICES = new Vector3[10] {new Vector3(0,0,0), new Vector3(10,10,10), new Vector3(30,10,50), new Vector3(30,40,50),
new Vector3(10,30,90), new Vector3(10,20,40), new Vector3(50,20,40), new Vector3(70,80,90),
new Vector3(10,70,20), new Vector3(60,10,0)};
lines = new List<LineRenderer>();
}
// Update is called once per frame
void Update () {
float x = Input.GetAxis ("Horizontal") * Time.deltaTime * SPEED;
float z = 0;
float y = Input.GetAxis ("Vertical") * Time.deltaTime * SPEED;
gameObject.transform.Translate (new Vector3(x,y,z));
}
void OnGUI() {
if (GUI.Button (new Rect(10,10,100,20), "Create"))
createString(TEST_VERTICES);
}
public bool createString( Vector3[] vertices ) {
LineRenderer lRend = gameObject.AddComponent ("LineRenderer") as LineRenderer;
//LineRenderer lRend = new LineRenderer();
lines.Add(lRend);
Debug.Log ("IS NULL"+(lRend == null).ToString ());
lRend.SetColors (new Color(100,0,0,100), new Color(0,0,100,100));
lRend.SetWidth(10, 1);
lRend.SetVertexCount(vertices.Length);
for (int i=0; i<vertices.Length; i++)
lRend.SetPosition(i, vertices[i]);
return true;
}
}
As Iridium points out, you can only add one component of each type to a gameobject. So you want to create a new game object for each new linerenderer. The simple way to do this here is to change:
LineRenderer lRend = gameObject.AddComponent("LineRenderer") as LineRenderer;
to:
LineRenderer lRend = new GameObject().AddComponent("LineRenderer") as LineRenderer;
Then if you need to access the linerenderer's gameobject later you can do so by lRend.gameObject. Or lines[index].gameObject.
A quick Google brings up this page: http://answers.unity3d.com/questions/47575/create-a-linerender-in-c.html which suggests that you cannot add multiple instances of the same type to a single GameObject, and suggests that multiple GameObject instances should be used instead.

Categories

Resources