Пример #1
0
        /// <summary>
        /// Helper for Organism.CollisionTest(). Looks for a collision between two cells,
        /// starting at the cell level then descending to the mesh level if required
        /// </summary>
        /// <param name="our"></param>
        /// <param name="his"></param>
        /// <returns></returns>
        public static bool CollisionTest(Cell our, Cell his)
        {
            // Do our spheres overlap? If not, we can't possibly collide
            if (Vector3.LengthSq(his.Location - our.Location) >
                (his.AbsSphere.Radius + our.AbsSphere.Radius) *
                (his.AbsSphere.Radius + our.AbsSphere.Radius))
                return false;

            // Our spheres WILL intersect. So, for each mesh in both cells, test to see if they will actually collide

            foreach (JointFrame ourMesh in our.collisionFrames)
            {
                foreach (JointFrame hisMesh in his.collisionFrames)
                {
                    bool result = Cytoplasm.CollisionTest(ourMesh, hisMesh);
                    if (result == true)
                        return true;
                }

            }
            return false;
        }
Пример #2
0
        /// <summary>
        /// Get a clone of this Cell from the library, loading it first if necessary
        /// </summary>
        /// <returns>A modifiable clone of the named Cell</returns>
        /// <param name="gene">The gene containing the cell's properties, orientation and wiring</param>
        /// <param name="owner">The organism that owns me</param>
        public static Cell Get(Gene gene, Organism owner)
        {
            Cell cell = null;

            // Get name of the cell from the gene
            string fullname = gene.XFile();

            // if the library already contains a Cell of that name, that's what we'll clone from
            if (library.ContainsKey(fullname))
            {
                cell = (Cell)library[fullname];
            //				Debug.WriteLine("	Cell: Created new Cell instance: "+name+":"+cell.instance);
            }
            // otherwise, create a new entry in the library by loading a whole X file
            else
            {
                cell = new Cell(fullname);
            //				Debug.WriteLine("	Cell: Created new Cell archetype: "+name+":"+cell.instance);
            }

            // Return a cloned instance of this Cell
            Cell newCell = cell.Clone(gene, owner);

            newCell.CreateBoundMarker();								// temp: create marker to show bounding sphere

            return newCell;
        }
Пример #3
0
        /// <summary>
        /// Return stats about the creature being edited, for display on the VDU
        /// </summary>
        public void Stats(out float radius, out float mass, out float bouyancy, out float resistance, 
            out Vector3 balance, out string name)
        {
            // Ensure the data is accurate after recent edits
            Refresh();															// Make sure that the trees and lists are up-to-date
            CalculateCG();														// Temporarily recalculate the CofG cell
            RecursiveUpdateFrames(rootCell);									// calculate cell positions
            ComputeBoundingSphere();											// update radius and centre

            radius = this.AbsSphere.Radius;										// org radius
            name = genome.Name;													// current name

            mass = 0;
            bouyancy = 0;
            resistance = 0;
            foreach (Cell c in partList)										// sum physical properties
            {
                mass += c.Physiology.Mass * scale;
                bouyancy += c.Physiology.Buoyancy * scale;
                resistance += c.Physiology.Resistance * scale;
            }

            balance = CGCell.AbsSphere.Centre - AbsSphere.Centre;				// distance of CG from geometric centre (on each WORLD axis)
            balance.Scale(1.0f / radius);										// as a fraction of creature's size

            // Clean up
            CGCell = rootCell;													// Set the CofG back to the root cell
        }
Пример #4
0
        /// <summary>
        /// Be magnetically attracted to the clamp (tractor beam).
        /// </summary>
        /// <param name="clamp">The location of the clamp</param>
        /// <returns>True if the organism is close enough to the clamp to become attached to it</returns>
        public bool Tractor(Vector3 clamp, Quaternion clampOrientation)
        {
            // If we're close to the clamp, return true and we'll get attached
            Vector3 targetVector = clamp - location;
            if (targetVector.LengthSq() < 1f)
                return true;

            // Switch off physics (it will get switched on again when re-released from clamp)
            Dynamic = false;
            CGCell = rootCell;

            // If we're a long way from underneath lab, aim for a point below lab first, so we don't pass through ship's wall
            if ((Math.Abs(targetVector.X) > 10f) || (Math.Abs(targetVector.Z) > 10f))
                targetVector.Add(new Vector3(0, -8, 0));

            // Apply a movement to bring the creature into alignment with the clamp or lower target
            targetVector.Normalize();
            MoveBy(Vector3.Scale(targetVector,Scene.ElapsedTime * 5f));

            // Rotate by a fraction of the difference between current rotation and that of clamp
            RotateTo(Quaternion.Slerp(Quaternion.RotationMatrix(rootCell.GetPlugMatrix()), clampOrientation, Scene.ElapsedTime * 1f));

            return false;
        }
Пример #5
0
 /// <summary>
 /// PREVIEW button pressed - temporarily add a new cell or delete it again when btn released
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="value"></param>
 public void btnPreviewChanged(Widget sender, Object value)
 {
     if (((bool)value == true) && (Lab.SelectedCell != null) && (Lab.SelectedSocket != null))
     {
         owner.Add();
         DrawCellData();
         previewed = Lab.SelectedCell;
     }
     else if (((bool)value == false) && (Lab.SelectedCell != null) && (Lab.SelectedCell == previewed))
     {
         Organism.DeleteCell();												// delete the selected cell
         DrawCellData();														// update the LCD
         previewed = null;
     }
 }
Пример #6
0
 /// <summary>
 /// Recursively create a new flat list of cells from the hierarchical one.
 /// </summary>
 /// <param name="cell"></param>
 private void BuildPartList(List<Cell> list, Cell cell)
 {
     list.Add(cell);
     if (cell.Sibling != null)
         BuildPartList(list, cell.Sibling);
     if (cell.FirstChild != null)
         BuildPartList(list, cell.FirstChild);
 }
Пример #7
0
 /// <summary>
 /// We've been asked to carry the camera. See if any cell in this organism will accept the role of camera mount.
 /// If so, store a reference to that cell and its hotspot for use by the camera.
 /// </summary>
 /// <returns>true if the camera was successfully assigned</returns>
 public bool AssignCamera()
 {
     foreach (Cell cell in partList)
     {
         int spot = cell.AssignCamera(cameraMount, cameraHotspot);
         if (spot!=-1)
         {
             cameraMount = cell;
             cameraHotspot = spot;
             return true;
         }
     }
     return false;
 }
Пример #8
0
        /// <summary>
        /// Return the socket number to which this other cell is connected
        /// </summary>
        /// <param name="other">the cell we're looking for</param>
        /// <returns>-2 if not found; -1 if the cell is on our plug; 0-n if the cell is on one of our sockets</returns>
        public int FindSocketNumberOf(Cell other)
        {
            // Are we the other's parent? If so, return the skt# to which it is attached
            if (this == other.parent)
                return other.parentSocket.Index;

            // Is other our parent? If so, return -1 because it is attached to our plug
            if (this.parent == other)
                return -1;

            // other isn't connected to us at all
            return -2;
        }
Пример #9
0
        /// <summary>
        /// Update all the cells' Combined transformation matrices (e.g. after relocating the cell).
        /// This ensures that the cells don't think they've been pushed with extreme force when being
        /// moved artificially!
        /// </summary>
        /// <param name="cell"></param>
        private void RecursiveUpdateFrames(Cell cell)
        {
            cell.UpdateFrames();

            // Now propagate the new combined matrices through to my siblings and children
            if (cell.Sibling != null)											// recurse through siblings
                RecursiveUpdateFrames(cell.Sibling);

            if (cell.FirstChild != null)										// recurse through children
                RecursiveUpdateFrames(cell.FirstChild);
        }
Пример #10
0
        private float totalMass = 0; // sum of all cell masses

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Construct a Creature instance from a genome
        /// </summary>
        /// <param name="genotype">The name of the xml file defining this creature, or "" if the creature is being created in the editor</param>
        /// <param name="location">world location of creature (Y should be zero)</param>
        /// <param name="orientation">world orientation of creature</param>
        public Organism(string genotype, Vector3 location, Orientation orientation)
        {
            Debug.WriteLine("Creating new Creature from genome: "+genotype);

            // Set relevant Renderable.FlagBits
            Dynamic = true;									// (Most) creatures respond to forces

            // Set basic members
            this.location = location;
            this.orientation = Quaternion.RotationYawPitchRoll(orientation.Yaw,orientation.Pitch,orientation.Roll);
            instance = instanceCount++;						// get a unique instance number
            name = genotype+instance.ToString("000");	    // give the creature a unique name (valid filename)

            // Set up other members
            if (genotype == "")
                this.genome = new Genome();                 // if no genotype supplied, create a default genome (Core cell only, for putting on the clamp)
            else
                this.genome = new Genome(genotype);	    	// otherwise, create our unique Genome object and store its ref

            // Load all the Cells from disk or the Cell Library, using the recipe in the Creature's genome
            // and establish their connection points
            partList = new Cell[1024];						// Create an initial partlist (will scrunch later)
            rootCell = GetCells(genome.Root, null);			// read the parts from the genome to create both the tree and partlist
            Cell[] shorter = new Cell[numParts];			// scrunch the partlist to the right size
            Array.Copy(partList,shorter,numParts);
            partList = shorter;

            // Now that the whole cell tree exists, allow the cells to connect up their channels
            rootCell.ClearAllChannels();
            rootCell.WireUpAllChannels();

            // Give the cells an absolute position in space so that we can calculate CG, bounds, etc.
            rootCell.Locate(Matrix.Translation(location));					// locate root cell temporarily at 0,0,0
            RecursiveUpdateFrames(rootCell);								// update the combined frames

            // Find out which cell is to act as the centre of gravity for the system
            CalculateCG();

            // Register the creature with the map and position it properly in space
            Map.Add(this);
            MoveTo(location);

            // Calculate the initial center and radius of the Creature's bounding sphere now it is located
            ComputeBoundingSphere();
            CheckMaps();													// And check maps again, because this requires sphere!

            // Calculate any aggregate properties required for sensor requests etc.
            SetAggregateProperties();

            // Set the SlowUpdate() timer to a random value, so that organisms do their slow updates
            // at different times
            SlowUpdateTimer = Rnd.Float(SLOWUPDATERATE);
        }
Пример #11
0
        /// <summary>
        /// Update this organism's cells
        /// To be called for ALL objects, whether visible or not, before rendering
        /// </summary>
        /// <param name="cell">The cell to update</param>
        private void RecursiveUpdate(Cell cell)
        {
            // Update this cell
            cell.Update();

            if (cell.Sibling != null)											// recurse through siblings
                RecursiveUpdate(cell.Sibling);

            if (cell.FirstChild != null)										// recurse through children
                RecursiveUpdate(cell.FirstChild);
        }
Пример #12
0
        /// <summary>
        /// Recursively walk the gene tree, extract the Cell filenames, clone the Cell from the library and
        /// record their interconnections (root->joint)
        /// </summary>
        /// <param name="gene">the gene being expressed</param>
        /// <param name="parent">the Cell that is the parent of this new one</param>
        /// <returns>the Cell created by this gene</returns>
        private Cell GetCells(Gene gene, Cell parent)
        {
            // Get the X filename from the gene and either load or fetch that Cell from the library,
            Cell s = Cell.Get(gene, this);

            // Add it to the flat partlist
            partList[numParts++] = s;

            // Locate this cell's SOCKET by locating the frame with the correct name in the
            // parent (if any)
            if (parent!=null)
                s.Attach(parent, gene.Socket);

            // if the gene has any siblings, recursively attach their structures as siblings of this one
            if (gene.Sibling!=null)
                s.Sibling = GetCells(gene.Sibling, parent);					// we share a parent

            // if the gene has a child, recursively attach this as the child of this one
            if (gene.FirstChild!=null)
                s.FirstChild = GetCells(gene.FirstChild, s);				// I am the parent

            return s;														// return the new Cell to the parent/sibling
        }
Пример #13
0
        /// <summary>
        /// Find out which cell is closest to the organism's centre of gravity.
        /// All future rotations and force calculations occur around CG cell rather than the root.
        /// NOTE: Don't call this until the cells have been given absolute locations
        /// </summary>
        private void CalculateCG()
        {
            Vector3 centre = new Vector3();
            Vector3 xyz = new Vector3();
            int n = partList.Length;

            // First, find the geographical centre of the creature (mean of all cells' locations)
            foreach (Cell c in partList)
                centre += c.Location;
            centre.X /= n;
            centre.Y /= n;
            centre.Z /= n;

            // find the distribution of mass around the centre
            foreach (Cell c in partList)
                xyz += (c.Location - centre) * c.Physiology.Mass;
            xyz.X /= n;
            xyz.Y /= n;
            xyz.Z /= n;

            // Adjust the CG to the centre of mass
            centre += xyz;

            // Find the cell nearest to this point
            Cell best = rootCell;
            float bestdist = float.PositiveInfinity;
            foreach (Cell c in partList)
            {
                float dist = Vector3.LengthSq(c.Location - centre);
                if (dist<bestdist)
                {
                    bestdist = dist;
                    best = c;
                }
            }

            // This is our CG cell. All rotations & forces will act around this cell
            CGCell = best;
        }
Пример #14
0
 /// <summary>
 /// The absolute location/orientation of this Cell is determined by its SOCKET on the parent Cell.
 /// This method locates the frame in the parent with the given (genetically defined) name
 /// and stores a reference to it in .socket
 /// Also stores a reference to the parent cell, to make it easier to walk up the tree
 /// </summary>
 /// <param name="parent">the Cell to which I'm connected</param>
 /// <param name="skt">the name of the socket to which I'm attached</param>
 public void Attach(Cell parent, string sktname)
 {
     try
     {
         parentSocket = JointFrame.FindBaseName(parent.RootFrame, sktname);
         this.parent = parent;
     }
     catch { }
     if (parentSocket == null)
     {
         throw new SDKException("Cell.FindSocket() was unable to connect cell [" + this.name + "] to parent socket [" + parent.name + "-" + sktname + "]");
     }
     //			Debug.WriteLine("	Connected cell ["+this.name+"] to parent socket ["+parent.name+"-"+sktname+"]");
 }
Пример #15
0
        /// <summary>
        /// Virtual method implemented by all Renderable objects.
        /// The given cell is in collision with our bounding sphere. Test to see if it actually collides with
        /// one of my parts. If so, return a Vector describing the force we exert on the offending cell
        /// (since we're an organism we'll receive a share of the force too, unlike scenery)
        /// </summary>
        /// <param name="cell">The cell that may have collided with us</param>
        /// <returns> Any force vector acting on the cell </returns>
        public override Vector3 CollisionTest(Cell otherCell)
        {
            Vector3 bounce = new Vector3();

            // Run through our own cells looking for a collision
            foreach (Cell ourCell in partList)
            {
                // Test more deeply by looking at the cell spheres then the
                // bounding boxes of each mesh in the cells
                if (Cell.CollisionTest(ourCell, otherCell) == true)
                {
                    // The bounce direction is a vector in the direction of our centre towards theirs
                    // (in other words, the two cells are treated as spheres and therefore bounce back away from
                    // their centres).
                    bounce = otherCell.AbsSphere.Centre - ourCell.AbsSphere.Centre;
                    bounce.Normalize();

                    // The length of the force vector is proportional to the objects' closing speed
                    Vector3 ourMvt = ourCell.Location - ourCell.OldLocation;			// how much we will move next frame
                    Vector3 hisMvt = otherCell.Location - otherCell.OldLocation;		// how much he will move next frame
                    float speed = Vector3.Length(ourMvt + hisMvt);					// combine to get closing movement
                    bounce.Scale(2.0f + speed * 10.0f);											// arbitrary scaling factor

                    // Also, a force acts on OUR cell, in the reverse direction.
                    // Distribute the two forces inversely proportional to mass
                    Vector3 ourBounce = -bounce;										// effect on us is the inverse of our effect on him
                    float mass = otherCell.Owner.TotalMass;								// get the masses of the two ORGANISMS (not cells)
                    float ourMass = ourCell.Owner.TotalMass;
                    bounce.Scale(ourMass / (ourMass + mass));							// distribute the forces proportionately
                    ourBounce.Scale(mass / (ourMass + mass));
                    ourCell.propulsionForce += ourBounce;								// apply our share as propulsion

                    // Once we've found a collision, we needn't look at any more of our cells
                    return bounce;
                }
            }

            return bounce;
        }
Пример #16
0
 /// <summary>
 /// Overload of Attach() to attach a cell to its parent given the actual attachment socket, rather than its name
 /// </summary>
 /// <param name="parent">the Cell to which I'm connected</param>
 /// <param name="skt">the actual socket to which I'm attached</param>
 public void Attach(Cell parent, JointFrame skt)
 {
     parentSocket = skt;
     this.parent = parent;
 }
Пример #17
0
        /// <summary>
        /// This organism has been selected for editing. Prepare it
        /// </summary>
        public void EditOn()
        {
            // Temporarily stop responding to physical forces
            Dynamic = false;

            // Force the CofG to the root cell, so that the organism sits properly atop the clamp
            CGCell = rootCell;

            // Select this organism, its root cell and first socket (if any)
            Lab.SelectedOrg = this;
            SelectFirst();
        }
Пример #18
0
 /// <summary>
 /// The given cell is in collision with our bounding sphere. Test to see if it actually collides with
 /// one of my parts. If so, return a Vector describing the force we exert on the offending cell.
 /// The default is to return nothing, but Scenery classes that are .Collidable will need to implement this.
 /// </summary>
 /// <param name="cell">The cell that may have collided with us</param>
 /// <returns> Any force vector acting on the cell </returns>
 public override Vector3 CollisionTest(Cell otherCell)
 {
     /// TODO: behaviour should depend on type
     return Vector3.Empty;
 }
Пример #19
0
        /// <summary>
        /// Actually render this organism's cells (recursively)
        /// </summary>
        /// <param name="cell"></param>
        public void RecursiveRender(Cell cell)
        {
            // Compute combined matrices and render this cell
            cell.Render((float)Math.Sqrt(DistSq));								// absolute dist from camera to obj sets LOD

            // Now propagate the new combined matrices through to my siblings and children
            if (cell.Sibling != null)											// recurse through siblings
                RecursiveRender(cell.Sibling);

            if (cell.FirstChild != null)										// recurse through children
                RecursiveRender(cell.FirstChild);
        }
Пример #20
0
        /// <summary>
        /// Given a bounding sphere (e.g. of a cell), calculate accurately whether this sphere intersects my surface.
        /// The tile being checked lies in the same quad as the cell, but the cell may not be over it.
        /// </summary>
        /// IF there's a collision, return the bounce vector.
        /// This determines the force acting on the cell that hit me.
        /// <param name="cell">The cell that may have collided with me</param>
        /// <returns>The bounce vector (0,0,0 if there's no collision)</returns>
        public override Vector3 CollisionTest(Cell cell)
        {
            Vector3 bounce = new Vector3();
            Vector3 cellCentre = cell.AbsSphere.Centre;
            float cellRadius = cell.AbsSphere.Radius * 1.1f;		// scale up because sphere lags behind reality

            // 1. Reject if the sphere lies horizontally outside this tile's bounding BOX
            //    i.e. is beyond the opposite or adjacent sides of the two triangles
            if ((cellCentre.X + cellRadius) < mesh[0].Position.X)			// too far west
                return bounce;
            if ((cellCentre.X - cellRadius) > mesh[1].Position.X)			// too far east
                return bounce;
            if ((cellCentre.Z + cellRadius) < mesh[2].Position.Z)			// too far south
                return bounce;
            if ((cellCentre.Z - cellRadius) > mesh[0].Position.Z)			// too far north
                return bounce;

            // 2. Reject if the cell is more than one radius above the highest point on the tile
            float max = mesh[0].Position.Y;
            if (mesh[1].Position.Y > max)
                max = mesh[1].Position.Y;
            if (mesh[2].Position.Y > max)
                max = mesh[2].Position.Y;
            if (mesh[3].Position.Y > max)
                max = mesh[3].Position.Y;
            if (cellCentre.Y > max + cellRadius)
                return bounce;

            //// 3. Reject if the sphere lies outside the plane of both triangles
            float dist0 = plane[0].Dot(cellCentre);
            float dist1 = plane[1].Dot(cellCentre);
            if ((dist0 > cellRadius) && (dist1 > cellRadius))
                return bounce;

            // 4. We're close enough to justify bounding-box checks for each mesh in the cell
            if (cell.CollisionTest(this.mesh) == false)
                return bounce;

            // If we get here, at least one point is in contact with the tile
            // Construct a bounce vector - the movement required to return us to the surface...
            //float dist0 = plane[0].Dot(cellCentre);
            //float dist1 = plane[1].Dot(cellCentre);

            // First, find which facet we've collided with. This will (presumably) be the one we're NEAREST
            // the surface of
            int facet = 0;
            if (dist1 < dist0)
            {
                facet = 1;
            }

            // Our closing speed with the surface will be the difference between out present distance and
            // our previous one
            float movement = (plane[facet].Dot(cell.OldLocation) - plane[facet].Dot(cell.Location))*10.0f;
            if (movement < 0) movement = 0;

            // The bounce vector will be the surface normal scaled by our closing speed
            movement = (movement * movement + 1.0f);
            bounce = Vector3.Scale(faceNormal[facet], movement);
            return bounce;
        }
Пример #21
0
 /// <summary>
 /// The given cell is in collision with our bounding sphere. Test to see if it actually collides with
 /// one of my parts. If so, return a Vector describing the force we exert on the offending cell
 /// </summary>
 /// <param name="cell">The cell that may have collided with us</param>
 /// <returns> Any force vector acting on the cell </returns>
 public virtual Vector3 CollisionTest(Cell otherCell)
 {
     // default is no force
     return Vector3.Empty;
 }