Unity Script only works with long namespace name - c#

I tried following this Unity ECS Entity Manager Tutorial from Turbo Makes Games.
I'm using Unity 2020.3.20f1.1086.
The Code works initially but I noticed, that Line 20 in SpawnEntitiesSystem.cs EntityManager.SetComponentData(newEntity, newPosition); stops working when I change or remove the namespace. After tinkering a bit with the code I can reproduce that the specific namespace is not important but the namespace has to be at least 18 characters long for the code to work as expected. If I change the namespace to 17 characters all entities are spawned at the same place. Other code after the faulty line 20 was executed but for readability I removed it from the code example. (Originally user input was also handled and in OnStartRunning a component was added to the new entitiy)
I only heard of similar problems in e.g. C++ when using pointer maths but I thought something like this shouldn't happen in C#. Does anyone have an idea what the core problem could be?
What I already tried without succes
restart Unity
delete Library, Obj and Logs folders
write code from scratch in new project
restart PC
SpawnEntitiesSystem.cs
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
namespace ALongNamespaceABCD {
public class SpawnEntitiesSystem : SystemBase {
private int2 _entitySpacing;
protected override void OnStartRunning() {
var entitySpawnData = GetSingleton<EntitySpawnData>();
var gridSize = entitySpawnData.SpawnGrid;
_entitySpacing = entitySpawnData.EntitySpacing;
for (int x = 0; x < gridSize.x; x++) {
for (int y = 0; y < gridSize.y; y++) {
var newEntity = EntityManager.Instantiate(entitySpawnData.EntityPrefab);
var newPosition = new LocalToWorld { Value = CalculateTransform(x, y) };
EntityManager.SetComponentData(newEntity, newPosition);
}
}
}
private float4x4 CalculateTransform(int x, int y) {
return float4x4.Translate(new float3 {
x = x * _entitySpacing.x,
y = 1f,
z = y * _entitySpacing.y
});
}
protected override void OnUpdate() {}
}
}
EntitySpawnData
using Unity.Entities;
using Unity.Mathematics;
[GenerateAuthoringComponent]
public struct EntitySpawnData : IComponentData {
public Entity EntityPrefab;
public int2 SpawnGrid;
public int2 EntitySpacing;
}
Edit:
I tried around a bit more and found out that it seems that the correct position will be set correctly at first. But it will instantly be overwritten by the prefabs Transform component. So maybe it has to do with converting the Prefab to an entity (I use the default Convert to Entity component) or a problem with some internal multithreading occurs.

Well, we finally got a response from Unity. Here is what they said:
This is intended behavior and will therefore be set to "won't fix".
The reasons are this:
Changing the name (and namespace) of a system changes its default position in the frame, this is expected behavior.
The SpawnEntitiesSystem from the provided repro project is not using any explicit system ordering attribute like
UpdateAfter/UpdateBefore/UpdateInGroup, so it follows the default.
Because it is expected behavior but nonetheless surprising, we have a task in the backlog about making the default order not depend on the
name in the future.
The prefab being instantiated has a Translation component and a Rotation component in addition to the LocalToWorld component.
The transform system from entities updates LocalToWorld based on the values of Translation and Rotation.
A direct modification of LocalToWorld conflicts with the transform system, and that modification will be overwritten.
Because Translation and Rotation are still at their default values, the expected outcome is that the transform system will compute an
identity LocalToWorld and put the instances back to the origin.
Unfortunately there is a bug in that particular setup (where the system doing the modification does it in OnStartRunning and executes
immediately after the transform system, if the namespace is long
enough to put it after the transform system) that causes the newly
spawned instances to never be noticed by the transform system. And it
is because of that bug that the cubes would show in the intended grid
layout by accident.
Source: https://issuetracker.unity3d.com/issues/entity-localtoworld-position-is-overwritten-by-prefab-position-when-namespace-is-17-characters-long-or-shorter
So, apparently, this whole situation happens because the LocalToWorld is sometimes being overwritten due to operation ordering that the length of the namespace is able to change. But this won't be the case in a future version.

A workaround is to set the Translation instead of the LocalToWorld Data.
Working code:
EntityManager.SetComponentData(newEntity, new Translation {
Value = new float3(
10.0f,
1.0f,
10.0f
)
});

Related

Changing materials properties during runtime

I am trying to alter my HDRP Lit material's emissive color and emissive intensity but it does not get reflected on my gameObjects. I have even tried using "_EmissionColor" and still there was no change. However the material that is suppose to change, shows as (Instance). What am I doing wrong here?
public GameObject[] myGOs;
private void Start () {
for(int i = 0; i<myGOs.Length; i++){
myGOs[i].GetComponent<Renderer>().material.SetColor("_EmissiveColor", new Vector4(0.8196f,0.783f,0,1) * 3.0f);
}
}
First, check if your material has this property - material.HasProperty("_EmissiveColor")
If, so, there is a trick which is usually applied in such cases - enable the keyword:
material.EnableKeyword("_EMISSION");
For your material the keyword can differ. You can find it among all shader keywords using material.shaderKeywords

Unable to get variables from script in other game object

I'm trying to generate 6 random ints, then assign them to 6 different objects, however I've found that simply generating the int within the object results in every number being the same, due to them all loading at identical times. To work around this issue I'm trying to generate the 6 in a row, so that the clock timing is different and gives a different number. I'm trying to figure out how to access these 6 variables.
I've tried a variety of different formats using 'GetComponent<>()' and 'GameObject.Find("")' together and storing the resulting script in a monobehaviour varibale (which I think is what might be messing me up), then trying to access the numbers through the variable I'm storing the script in. But when I do this, unity says there is no number variable (or Num1, Num2, etc. in my case) in the script.
Here is what I have, I'll only show the code trying to acquire the variables as I have verified that the variable generation works.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class NumberButton : MonoBehaviour
{
public int Num;
public GameObject Game;
void Start()
{
MonoBehaviour Game = GameObject.Find("Game").GetComponent<GameInit>();
print(Game.name);
if (gameObject.name == "Button1")
{
Num = Game.Num1;
}
else if (gameObject.name == "Button2")
{
Num = Game.Num2;
}
//There are 4 more of these, 1 for each button, I realize this is terrible code etiquette.
GetComponent<TextMesh>().text = Num.ToString();
}
}
If it works, each button should be assigned their variable based on their name, so Button1 gets Num1 from the GameInit script stored in the GamObject "Game". In actuality nothing is grabbed from GameInit, all the Num variables in the grabber objects are equal to 0, despite the variables in GameInit not being 0.
EDIT
Sorry, I misread exactly what your issue was. The compiler is telling you that those variables do not exist in the MonoBehaviour object, because MonoBehaviour does not have those variables.
You need to change
MonoBehaviour Game = GameObject.Find("Game").GetComponent<GameInit>();
To
GameInit Game = GameObject.Find("Game").GetComponent<GameInit>();
ORIGINAL
I can't yet comment due to low rep so I am going to have this as an answer.
Firstly, is the number generation happening in GameInit.Start()? If so, it is possible that the button Start()s are being called before GameInit.Start() and so all of the variables are the default value of 0 at the time of access. To ensure that this is not the case, put the number generation code in GameInit.Awake().
Also, to ensure that there is no hocus pocus happening with the MonoBehaviour object, try this:
...
if (gameObject.name == "Button1")
{
Num = GameObject.Find("Game").GetComponent<GameInit>().Num1;
}
...

How to change an input field's content type in c# script with Unity?

I'm using Unity 4.6.9, coding in c#, and all I'm trying to do is change what starts as an input field with an Integer content type and a character limit of 2, to one that has a Standard content type and a larger character limit. I've created the object itself using Unity itself, so I can't figure out how to change it in the script. What i'm trying to do is have a single field be responsible for 2 integers and a string input, and i have the entirety of the code completely working, EXCEPT for changing the type and limit while the program is running. I've been googling and trying things for almost 2 hours now, so I'm hoping I didn't just miss something. I've already tried looking through Unity's documentation and that hasn't helped me what-so-ever.
For the purpose of answering this, my Input Field is named InputField, the class it's in is named UIInputField, and the actual output from that field is named tempInput (the data that gets sent from that field into the program). And like I said, I'm just trying to change "Content Type" and "Character Limit", I've already got the code worked out to convert strings to ints, as well as a failsafe if the input field is left blank, or has the wrong character type.
if I've left anything out that is necessary for this question to be answerable, let me know.
EDIT: Sorry, I left out the code thinking it wouldn't be necessary (thought this would be an easy fix that I just hadn't figured out yet) So here's the code for what I've got so far (I do know that there are portions of this program that could create an issue depending on what the user puts in, and already know how to fix it, but I'm trying to see about getting this input issue working properly before I worry about those issues):
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
public class UIInputField : MonoBehaviour {
string[] particNames;
string[] particInit;
int subState = 1;
int state = 1;
int particVar;
// Update is called once per frame
void Update () {
}
//Fix substate handling before building.
public void getInt(string tempInput){
if (state == 1) {
if (Int32.TryParse (tempInput, out particVar))
Debug.Log (particVar);
particNames = new string[particVar];
particInit = new string[particVar];
GameObject.Find ("InputField").characterLimit = 12;
GameObject.Find ("InputField").ContentType = standard;
state++;
} else if (state == 2) {
particNames [subState] = particVar;
subState++;
GameObject.Find ("InputField").characterLimit = 2;
GameObject.Find ("InputField").ContentType = integerNumber;
if (subState == particNames.Length){
state++;
subState = 1;
}
} else if (state == 3) {
if (Int32.TryParse (tempInput, out particVar))
Debug.Log (particVar);
particInit[subState] = particVar;
subState++;
if (subState == particNames.Length) /* The code to move on the the next portion of this program will be here once this portion is working properly*/;
}
}
}
After doing more searching over the past couple days, I found the answer to this question. It uses:
mainInputField.contentType = InputField.ContentType.Standard;
mainInputField.characterLimit = 12;//Or any integer
mainInputField is just a variable at this point, of type InputField, and you have to go into the UnityEditor to set that variable to reference the actual input field variable.

Farseer Assertion Failure

We're creating a game for a school project. It's a 2D platformer and it is in its very early stages. We use C#/XNA and we're implementing Farseer Physics Engine.
I'm currently struggling with the map-class. In the class we have a List of DrawableGameObjects, were we store each tile of the map and draw them. But when we try to draw them we get a "Assertion Failed". Examining the problem even further I've come to the conclusion that whenever we try to add more than to static bodies to the world (even without drawing them) we get this failure. Throw message
Game1.cs:line 210 is:
world.Step(0.033333f);
And Program.cs:line 15 is:
game.Run();
Here is the code for the Map class:
class Map
{
private List<DrawableGameObject> ground = new List<DrawableGameObject>();
public Map(World world, Texture2D texture)
{
for (int i = 0; i < 32; i++)
{
DrawableGameObject floor = new DrawableGameObject(world, texture, new Vector2(40, 40), 100, "ground");
floor.Position = new Vector2(i * 40, 500);
floor.body.BodyType = BodyType.Static;
ground.Add(floor);
}
}
public void Draw(SpriteBatch spriteBatch){
foreach (DrawableGameObject dgo in ground)
dgo.Draw(spriteBatch);
}
}
Any ideas? I've posted the problem on Farseer's forum, but they haven't been very helpful yet...
This is a bug in Farseer. (Version 3.3.1)
I opened up the Farseer source code to the method in question (World.SolveTOI) and found two calls to Debug.Assert. And, in fact, in my copy of the code, I've actually already come across this bug and commented one of them out, specifically:
Debug.Assert(typeA == BodyType.Dynamic || typeB == BodyType.Dynamic);
Basically it doesn't want to attempt to handle contacts between two bodies that are static.
Fortunately the code immediately below actually checks for essentially the same condition, and continues the loop if that is the case:
bool awakeA = bA.Awake && typeA != BodyType.Static;
bool awakeB = bB.Awake && typeB != BodyType.Static;
// Is at least one body awake?
if (awakeA == false && awakeB == false)
{
continue;
}
So it's quite safe to simply comment out or remove the assertion. (You should, of course, be building Farseer from source - it makes life much easier.)
To reproduce the Farseer bug: Have two static bodies and one dynamic body that is in contact with both, then make the dynamic body static. The assert will trigger.
The assert is in the contact handling loop. Normally a pair of static bodies wouldn't create contacts. But if a body starts out as dynamic, contacts can be created - they don't get removed when the body is made static.

OnCollision event handler problems in C# XNA with Farseer Physics

I have this working ok(ish) in my game at the moment, but i'm not fantastic at maths. When two primatives collide, I want them to smash up into tiny bits if the force applied to a primative was over a set threshold. My collision event handler at present looks like this.
public bool Collision(Fixture fixtureA, Fixture fixtureB, Manifold manifold)
{
Vector2 position = manifold.LocalNormal;
float angle = (float)Math.Atan2(position.Y, position.X);
Vector2 force = Vector2.Zero;
if (angle < 0)
force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi + angle) * fixtureA.Body.LinearVelocity.Y);
else
force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi - angle) * fixtureA.Body.LinearVelocity.Y);
double XForce = Math.Sqrt(force.X * force.X);
double YForce = Math.Sqrt(force.Y * force.Y);
double totalForce = XForce + YForce;
if ((Breakable) && (totalForce > BreakForce))
{
Breakable = false;
Active = false;
BreakUp(fixtureA, fixtureB);
}
return true;
}
I put that in a LONG time ago when I was just playing around. This causes a bit of a problem in certain situations. For example, if a primative is stationary on the floor and another primative falls onto it from a decent height, almost always, the falling box blows up and the resting box survives. Also if two boxes are falling side by side and give each other the tinyest of touches, then both boxes blow up mid air. Hmmmmm, not really perfect that. Does anyone have any idea how to improve my collision handler? Thanks in advance.
Ok, so my other answer is viable. But I've looked at Farseer 3.0 (the current SVN version) more closely and found that it already implements almost exactly what you are trying to do.
Look for "BreakableBody.cs". You may be able to directly use that - but otherwise you could just copy out the functionality you want.
Specifically: Instead of attaching a function to your fixture's OnCollision you want to attach one to PostSolve. It takes a ContactConstraint which you can dive into and find the impulses from the collision.
This is the implementation of that function used by BreakableBody:
private void PostSolve(ContactConstraint contactConstraint)
{
if (!Broken)
{
float maxImpulse = 0.0f;
for (int i = 0; i < contactConstraint.manifold.PointCount; ++i)
{
maxImpulse = Math.Max(maxImpulse,
contactConstraint.manifold.Points[0].NormalImpulse);
maxImpulse = Math.Max(maxImpulse,
contactConstraint.manifold.Points[1].NormalImpulse);
}
if (maxImpulse > Strength)
{
// Flag the body for breaking.
_break = true;
}
}
}
Apparently the impulse data in the manifolds is only set correctly in PostSolve, not in OnCollision.
(While this is currently the accepted answer - I would direct anyone to my other answer for a potentially superior approach.)
Your calculation of impact force is completely wrong. You need to get the relative velocity at the contact point(s) - you're getting something quite strange...
Your code looks like it's using Farseer 3.0 (you should specify, because that's more of a fork of Box2DX than Farseer 2.1). What I did in Farseer 2.1 (where you've got ContactList contacts instead of a Manifold) to get the impact velocity was:
foreach(Contact contact in contacts)
{
Vector2 position = contact.Position;
Vector2 v0;
me.Body.GetVelocityAtWorldPoint(ref position, out v0);
Vector2 v1 = new Vector2();
if(!hit.Body.IsStatic)
hit.Body.GetVelocityAtWorldPoint(ref position, out v1);
v0 -= v1;
float hitVelocity = v0.Length();
// To then get the force, you need the mass of the two objects
}
From a brief look at the Farseer 3.0 source, it seems that Manifold has a member:
public FixedArray2<ManifoldPoint> Points;
And both Manifold and ManifoldPoint have members:
public Vector2 LocalPoint;
It should be fairly simple to modify my Farseer 2.1 code to use those instead.
Also: I recommend simply marking the two objects as needing to break, and then actually breaking them after your physics update finishes running (rather than in the collision handler).
I haven't used XNA, but as a physics problem, why not just subtract the linear velocity of A from the linear velocity of B, and get the 'force' as the square of the resulting vector (sum the squares of the components)? That should harmonize with the kinetic energy involved according to `E=(mv^2)/2', for a very simple physical model, even if we are ignoring the masses (or, for that matter, elasticity or the distinction between energy and momentum). If the objects are moving in the same general direction at the same speed, you get a small value; if one is approaching (or, of course, departing!) at high speed, you get a large value.

Categories