LocalScale and Rotation problem (work in Inspector but not in script)

Hi everyone !

I have a problem with the transform.position.

I want to create a ball moving on a plane which is in anywhere in the world. So I made a script for the ball trajectory in the plane. I used localPosition. This attribute compute the parent transform on the child so I shouldn’t have to worry about the rotation and position of the plane. It should work in any position & rotation.

The thing is that when the plane is at (0, 0, 0) position and (0, 0, 0) rotation, it works perfectly.
So I tried to rotate the plane with this line :

Plan.transform.rotation = Quaternion.Euler(-45,10,30);

May be I need to precise that my plane is a child of an empty gameObject with a transform of (0, 0, 0) in position and rotation.

My plane is rotated but the ball does not collide (virtually, no collider) with the edges of the plane.

And there is a weird thing. When I put my plane horizontally (rotation to (0, 0, 0)) and I change the transform rotation values of the plane in the inspector, it works very well !

There is my code :
The mesh for the plane :

#pragma strict

var Plan : GameObject;
var center : boolean = true;
var size : Vector2 = new Vector2 (10, 10);
var resolutionX : int = 10;
var resolutionZ : int = 10;
private var newVertices : Vector3[] = new Vector3[(resolutionX + 1) * (resolutionZ + 1)];
private var newTriangles : int[] = new int[resolutionX * resolutionZ * 6];
private var newUvs : Vector2[] = new Vector2[newVertices.Length];

function Start () {
if (gameObject.Find("PlanePivot").transform.Find("Forme").gameObject == null) {
Plan = GameObject("Forme");
Plan.transform.parent = gameObject.Find("PlanePivot").transform;
}
else {
Plan = gameObject.Find("PlanePivot").transform.Find("Forme").gameObject;
}
Plan.AddComponent(MeshFilter);
Plan.AddComponent(MeshRenderer);
// load the resource PlaneMaterial from folder Assets/Resources
var mat : Material = Resources.Load("PlaneMaterial", Material);
Plan.renderer.material = mat;
Plan.AddComponent(MeshCollider);
Plan.transform.parent = gameObject.Find("PlanePivot").transform;
// la limite peut être abaissée mais il faut éviter une taille nulle car le mesh deviendra invisible
if (size.x < 0.1f)
size.x = 0.1f;
if (size.y < 0.1f)
size.y = 0.1f;
resolutionX = Mathf.Clamp (resolutionX, 1, 250);
resolutionZ = Mathf.Clamp (resolutionZ, 1, 250);

CreateMesh ();
OtherFace();

//Plan.transform.rotation = Quaternion.Euler(-45,10,30);
}

// reconstruct mesh based on size and resolution
function CreateMesh () {
// update size of newVertices and newTriangles
newVertices = new Vector3[(resolutionX + 1) * (resolutionZ + 1)];
newTriangles = new int[resolutionX * resolutionZ * 6];
newUvs = new Vector2[newVertices.Length];

// int i sert juste à accéder aux éléments des tableaux simplement
var i : int = 0;

// create vertices
for (var z : int = 0; z <= resolutionZ; z++) {
for (var x : int = 0; x <= resolutionX; x++) {
newVertices = Vector3 (x * size.x / resolutionX, 0, z * size.y / resolutionZ);
if (center) {
newVertices -= Vector3 (size.x / 2, 0, size.y / 2);
}
// le cast en float sert à éviter la division entière de 2 int
newUvs = Vector2 ((x*1.0) / resolutionX, (z*1.0) / resolutionZ);
i++;
}
}

i = 0;
// create triangles
for (z = 0; z < resolutionZ; z++) {
for (x = 0; x < resolutionX; x++) {
newTriangles[i + 5] =
newTriangles[i ] = z * (resolutionX + 1) + x;
newTriangles[i + 1] = (z + 1) * (resolutionX + 1) + x;
newTriangles[i + 2] =
newTriangles[i + 3] = (z + 1) * (resolutionX + 1) + x + 1;
newTriangles[i + 4] = z * (resolutionX + 1) + x + 1;
i += 6;
}
}

//create a new mesh, assign the vertices and triangles
var newMesh : Mesh = new Mesh ();
newMesh.name = "Procedural Plane"; 
newMesh.Clear ();
// cette ligne sert à nettoyer les données du mesh
// Unity vérifie si les indices des tris ne sont pas en dehors du tableau
// de vertices, ce qui peut facilement se produire si on en assigne de
// nouveaux alors que le mesh contient toujours les anciens tris
// (vous obtiendrez une jolie exception dans ce cas !)
newMesh.vertices = newVertices;
newMesh.uv = newUvs;
//newMesh.colors = colors;
newMesh.triangles = newTriangles;
newMesh.RecalculateNormals(); //recalculate normals, bounds and optimize
newMesh.RecalculateBounds();
newMesh.Optimize();

(Plan.GetComponent(MeshFilter) as MeshFilter).mesh = newMesh; //assign the created mesh as the used mesh 
Plan.GetComponent(MeshCollider).sharedMesh = null;
Plan.GetComponent(MeshCollider).sharedMesh = newMesh; 
}

function OtherFace () {
var mesh = gameObject.Find("Forme").GetComponent(MeshFilter).sharedMesh;
var vertices = mesh.vertices;
var uv = mesh.uv;
var normals = mesh.normals;
var szV = vertices.length;
var newVerts = new Vector3[szV*2];
var newUv = new Vector2[szV*2];
var newNorms = new Vector3[szV*2];
for (var j=0; j< szV; j++){
// duplicate vertices and uvs:
newVerts[j] = newVerts[j+szV] = vertices[j];
newUv[j] = newUv[j+szV] = uv[j];
// copy the original normals...
newNorms[j] = normals[j];
// and revert the new ones
newNorms[j+szV] = -normals[j];
}
var triangles = mesh.triangles;
var szT = triangles.length;
var newTris = new int[szT*2]; // double the triangles
for (var i=0; i< szT; i+=3){
// copy the original triangle
newTris = triangles;
newTris[i+1] = triangles[i+1];
newTris[i+2] = triangles[i+2];
// save the new reversed triangle
j = i+szT; 
newTris[j] = triangles+szV;
newTris[j+2] = triangles[i+1]+szV;
newTris[j+1] = triangles[i+2]+szV;
}
mesh.vertices = newVerts;
mesh.uv = newUv;
mesh.normals = newNorms;
mesh.triangles = newTris; // assign triangles last!
}

The ball script :

#pragma strict
//field variables
var fieldHeight : float;
var fieldWidth : float;
var field : GameObject;

//ball variables
var ball : GameObject;
var ballDirX : float = 0.1;
var ballDirZ : float = 0.1;
var ballSpeed : float = 0.1;
var goBall : boolean = true;

var D : Vector3;
var Forme : GameObject;

function Start () {

Forme = gameObject.Find("PlanePivot").transform.Find("Forme").gameObject;

ball = GameObject.CreatePrimitive(PrimitiveType.Sphere);
ball.transform.parent = Forme.transform;
ball.name = "Ball";
ball.transform.localPosition = Vector3(0, 0, 0);

Forme.transform.localEulerAngles = new Vector3(-45,10,30); 

ball.renderer.enabled = false;

var t : Transform = Forme.transform;
var size : Vector3 = t.renderer.bounds.size;

fieldWidth = size.x;
fieldHeight = size.z;

Debug.Log("width : "+fieldWidth+" height : "+fieldHeight);
}

function Update () {
if (Forme.renderer.isVisible) {
ball.renderer.enabled = true;
//if (goBall) {
ballPhysics();
// }
}
}

function ballPhysics() {

// update ball position in the plane frame
ball.transform.localPosition.x += ballDirX * ballSpeed;
ball.transform.localPosition.z += ballDirZ * ballSpeed;
// if ball goes off the 'left' side (Player's side)
if (ball.transform.localPosition.x <= -fieldWidth/2) {
// Player1 scores ++
// update scoreboard in GUI
// reset ball to center
//goBall = false;
resetBall(2);
//matchScoreCheck();
}
// if ball goes off the 'right' side (CPU's side)
if (ball.transform.localPosition.x >= fieldWidth/2) { 
// Player2 scores ++
// update scoreboard GUI
// reset ball to center
//goBall = false;
resetBall(1);
//matchScoreCheck();
}
// if ball goes off the bottom side (side of table)
if (ball.transform.localPosition.z <= -fieldHeight/2) {
ballDirZ = -ballDirZ;
} 
// if ball goes off the top side (side of table)
if (ball.transform.localPosition.z >= fieldHeight/2) {
ballDirZ = -ballDirZ;
}

Debug.Log("Local : X : "+ball.transform.localPosition.x+" Y : "+ball.transform.localPosition.y+" Z : "+ball.transform.localPosition.z);
Debug.Log("Global : X : "+ball.transform.position.x+" Y : "+ball.transform.position.y+" Z : "+ball.transform.position.z);

// limit ball's y-speed to 2x the x-speed
// this is so the ball doesn't speed from left to right super fast
// keeps game playable for humans
if (ballDirX > ballSpeed * 2) {
ballDirX = ballSpeed * 2;
}
else if (ballDirX < -ballSpeed * 2) {
ballDirX = -ballSpeed * 2;
} 
}

function resetBall(loser) {
Debug.Log("reset");
// position the ball in the center of the table
ball.transform.localPosition.x = 0;
ball.transform.localPosition.y = 0;
ball.transform.localPosition.z = 0;

// if player lost the last point, we send the ball to opponent
if (loser == 1) {
ballDirX = -0.1;
}
// else if opponent lost, we send ball to player
else {
ballDirX = 0.1;
}

// set the ball to move towards the top of the plane
ballDirZ = 0.1;
}​

Thank you for your help !!

Usually you shouldn’t be setting the position of the object yourself with ball.transform.localPosition. Instead you should have a rigid body component on your object and control it somewhat like this:

Vector3 directionalForce = GetMovementSomehow();
ball.GetComponent<Rigidbody>().AddForce(directionalForce);

That way the physics engine keeps control of the object action and reaction.