// GhostMode - Makes physical walls passable, and spiritual walls solid (only to the marble). protected virtual void GhostMode() { Physics.IgnoreCollision(ghostWall, marble.GetComponent <Collider>(), physical); gameObject.layer = (physical)? LayerMask.NameToLayer("Ignore Raycast") : LayerMask.NameToLayer("Default"); StopAllCoroutines(); if (!physical) { StartCoroutine("FadeIn"); } }
// Returns a list of float defining the state of the agent public override List <float> CollectState() { List <float> state = new List <float>(); // @note: we handle changing state size (i.e. more marbles) by applying state size to the brain based on the number of marbles // we get the bottomest marble only with negative velocity (i.e. the one that is going down!) // this is because we cannot change state size with the curriculum, so we cannot just add more marbles and check all of them // also, we are not interested in high marbles, after all // @note: we could check the two bottomest marbles if needed Marble riskyestMarble = marbles[0]; if (!stateUseAllMarbles) { for (var mi = 1; mi < nMarbles; mi++) // Only the first nMarbles are considered { var marble = marbles[mi]; var velOld = riskyestMarble.GetComponent <Rigidbody>().velocity.y; var velNew = marble.GetComponent <Rigidbody>().velocity.y; // TODO: cache RB into marble itself so we do not call GetComponent if (velNew < velOld) { // going down-er! riskyestMarble = marble; } else if (Math.Abs(velNew - velOld) < 0.01f) { if (marble.transform.position.y < riskyestMarble.transform.position.y) { riskyestMarble = marble; } } } foreach (var marble in marbles) { marble.GetComponentInChildren <MeshRenderer>().material.color = Color.white; } riskyestMarble.GetComponentInChildren <MeshRenderer>().material.color = Color.red; } for (var mi = 0; mi < nMarbles; mi++) // Only the first nMarbles are considered { var marble = marbles[mi]; var usedMarble = marble; if (!stateUseAllMarbles) { usedMarble = riskyestMarble; } // Marble Position (+3) // @note: normalized and relative to agent's position if (stateUseMarblePosVelXZ) { state.Add((usedMarble.transform.position.x - transform.position.x) / (gridSize / 2f)); } if (stateUseMarblePosVelY) { state.Add((usedMarble.transform.position.y - transform.position.y) / (areaHeight)); } if (stateUseMarblePosVelXZ) { state.Add((usedMarble.transform.position.z - transform.position.z) / (gridSize / 2f)); } // TODO: marbles should have a MAX SPEED // Marble Speed (+3) // @note: normalized based on max velocity var marbleRB = usedMarble.transform.GetComponent <Rigidbody>(); var marbleVelocity = marbleRB.velocity; if (stateUseMarblePosVelXZ) { state.Add(Mathf.Clamp(marbleVelocity.x, -maxMarbleVelocity, maxMarbleVelocity) / maxMarbleVelocity); } if (stateUseMarblePosVelY) { state.Add(Mathf.Clamp(marbleVelocity.y, -maxMarbleVelocity, maxMarbleVelocity) / maxMarbleVelocity); } if (stateUseMarblePosVelXZ) { state.Add(Mathf.Clamp(marbleVelocity.z, -maxMarbleVelocity, maxMarbleVelocity) / maxMarbleVelocity); } // TODO: marbles should have a MAX angular velocity // Marble Angular Velocity (+3) var marbleAngularVelocity = marbleRB.angularVelocity; if (stateUseMarblePosVelXZ) { state.Add(Mathf.Clamp(marbleAngularVelocity.x, -maxMarbleVelocity, maxMarbleVelocity) / maxMarbleVelocity); } if (stateUseMarblePosVelY) { state.Add(Mathf.Clamp(marbleAngularVelocity.y, -maxMarbleVelocity, maxMarbleVelocity) / maxMarbleVelocity); } if (stateUseMarblePosVelXZ) { state.Add(Mathf.Clamp(marbleAngularVelocity.z, -maxMarbleVelocity, maxMarbleVelocity) / maxMarbleVelocity); } if (!stateUseAllMarbles) { break; // Only one } } foreach (var block in blocks) { // Block trigger time (+1) if (stateUseBlockTriggerTime) { state.Add(block.CurrentTriggerTime); } // Block position (+2) if (stateUseBlockPos) { state.Add((block.transform.position.x - transform.position.x) / (gridSize / 2f)); //state.Add((block.transform.position.y - transform.position.y) / (gridSize / 2f)); state.Add((block.transform.position.z - transform.position.z) / (gridSize / 2f)); } // Block rotation (+3) if (stateUseBlockRot) { state.Add(block.transform.localEulerAngles.x / blockRotationAngleLimit); state.Add(block.transform.localEulerAngles.y / blockRotationAngleLimit); state.Add(block.transform.localEulerAngles.z / blockRotationAngleLimit); } // Block velocity (+2) if (stateUseBlockVel) { // TODO: range -1,1 //var blockRb = block.GetComponent<Rigidbody>(); //var blockVel = blockRb.velocity; state.Add(Mathf.Clamp(block.speed.x, -maxBlockVelocity, maxBlockVelocity) / maxBlockVelocity); //state.Add(Mathf.Clamp(blockVel.y, -maxBlockVelocity, maxBlockVelocity) / maxBlockVelocity); state.Add(Mathf.Clamp(block.speed.z, -maxBlockVelocity, maxBlockVelocity) / maxBlockVelocity); } } if (verboseState) { string statesString = "State:"; for (int i = 0; i < state.Count; i++) { statesString += " " + state[i] + "\n"; } Debug.Log(statesString); } return(state); }