Пример #1
0
 public TrunkMetamerConstraint(Metamer metamer, Vector2 anchorPoint, float distance)
     : base(ConstraintType.TRUNK)
 {
     this.metamer = metamer;
     this.anchorPoint = anchorPoint;
     this.distance = distance;
 }
        public DistanceMetamerConstraint(Metamer metamerA, Metamer metamerB, float distance, float stiffness)
            : base(ConstraintType.DISTANCE)
        {
            this.metamerA = metamerA;
            this.metamerB = metamerB;
            this.distance = distance;
            this.stiffness = stiffness;

            Debug.Assert(!metamerA.isBroken);
            Debug.Assert(!metamerB.isBroken);

            // Square root approximations variables
            distanceSq = distance * distance;

            metamerB.relatedConstraints.Add(this);
        }
Пример #3
0
        // assembleShoot
        private Metamer assembleShoot()
        {
            // Initial metamer conditions for the head metamer
            BudType initialActiveBud = tree.maxShootLength > 1 ? BudType.LATERAL : BudType.TERMINAL;
            BudState initialTerminalBudState = tree.maxShootLength > 1 ? BudState.NODE : BudState.DORMANT;
            BudState initialLateralBudState = BudState.DORMANT;
            //float initialAxis = (float)Math.Atan2(optimalGrowthDirection.Y, optimalGrowthDirection.X);

            // Calculate the growth direction
            Vector2 newGrowthDirection = new Vector2((float)Math.Cos(axis), (float)Math.Sin(axis));
            newGrowthDirection += (optimalGrowthDirection * tree.optimalGrowthWeight);
            newGrowthDirection += (tree.tropism * tree.tropismWeight);
            newGrowthDirection.Normalize();
            float initialAxis = (float)Math.Atan2(newGrowthDirection.Y, newGrowthDirection.X);

            // Calculate the shoot length
            int shootLength = (int)(budQuality * tree.maxShootLength);
            bool recalculateDistance = false;
            Vector2 hitPoint = Vector2.Zero;
            tree.treeSystem.physicsSystem.getWorld(tree.levelUid).RayCast((Fixture fixture, Vector2 point, Vector2 normal, float fraction) =>
            {
                int entityId = (int)fixture.Body.UserData;
                if (tree.treeSystem.entityManager.getComponent(tree.levelUid, entityId, ComponentType.IgnoreTreeCollision) != null)
                    return fraction;

                recalculateDistance = true;
                hitPoint = point;
                return fraction;
            },
                position,
                position + newGrowthDirection * ((float)shootLength * tree.internodeLength));
            if (recalculateDistance)
                shootLength = (int)Math.Floor((hitPoint - position).Length());

            if (shootLength > 0)
            {
                Metamer head = new Metamer(tree, this, initialActiveBud, initialTerminalBudState, initialLateralBudState, initialAxis, !placeBudOnLeft);
                Metamer tail = head;
                for (int i = 1; i < shootLength; i++)
                {
                    bool onLastMetamer = i == shootLength - 1;
                    BudType subsequentActiveBud = onLastMetamer ? BudType.TERMINAL : BudType.LATERAL;
                    BudState subsequentTerminalBudState = onLastMetamer ? BudState.DORMANT : BudState.NODE;
                    BudState subsequentLateralBudState = BudState.DORMANT;

                    // Add metamer onto most recently created metamer
                    tail.mainMetamer = new Metamer(
                        tree,
                        tail,
                        subsequentActiveBud,
                        subsequentTerminalBudState,
                        subsequentLateralBudState,
                        initialAxis,
                        !tail.placeBudOnLeft);

                    // Store tail metamer
                    tail = tail.mainMetamer;
                }
                tail.isTail = true;

                // Create distance constraint between this metamer and the tail
                constraints.Add(new DistanceMetamerConstraint(this, tail, (position - tail.position).Length(), 1f));

                return head;
            }

            return null;
        }
Пример #4
0
        // appendNewShoots
        public void appendNewShoots()
        {
            if (isBroken)
                return;

            // Chain metamer calls
            if (mainMetamer != null)
                mainMetamer.appendNewShoots();
            if (lateralMetamer != null)
                lateralMetamer.appendNewShoots();

            if (activeBud != BudType.NONE)
            {
                // Check bud quality
                if (budQuality > 0)
                {
                    // Create shoots...
                    Debug.Assert(activeBud != BudType.NONE);
                    if (activeBud == BudType.TERMINAL)
                    {
                        if (terminalBudState != BudState.DEAD)
                        {
                            mainMetamer = assembleShoot();
                            terminalBudState = mainMetamer == null ? BudState.DEAD : BudState.NODE;
                        }
                        activeBud = BudType.LATERAL;
                    }
                    else if (activeBud == BudType.LATERAL)
                    {
                        if (lateralBudState != BudState.DEAD)
                        {
                            lateralMetamer = assembleShoot();
                            lateralBudState = lateralMetamer == null ? BudState.DEAD : BudState.NODE;
                        }
                        activeBud = BudType.NONE;
                    }
                }
            }
        }
Пример #5
0
        // kill
        private void kill()
        {
            string levelUid = tree.levelUid;

            if (mainMetamer != null)
                mainMetamer.kill();
            if (lateralMetamer != null)
                lateralMetamer.kill();

            // Remove from metamer grid
            tree.treeSystem.metamerGrid[levelUid][ci][cj].Remove(this);
            if (tree.treeSystem.metamerGrid[levelUid][ci][cj].Count == 0)
                tree.treeSystem.metamerGrid[levelUid][ci].Remove(cj);
            if (tree.treeSystem.metamerGrid[levelUid][ci].Count == 0)
                tree.treeSystem.metamerGrid[levelUid].Remove(ci);

            // Should have no bodies or mouse joints
            Debug.Assert(body == null);
            Debug.Assert(mouseJoint == null);

            // Clear connections
            mainMetamer = null;
            lateralMetamer = null;
            if (previousMetamer != null)
            {
                if (previousMetamer.mainMetamer == this)
                    previousMetamer.mainMetamer = null;
                else if (previousMetamer.lateralMetamer == this)
                    previousMetamer.lateralMetamer = null;
            }
            previousMetamer = null;

            // Clear lists
            constraints.Clear();
            relatedConstraints.Clear();
            constraintPoints.Clear();
            previousConstraintPoints.Clear();
            collisionNormals = null;
            collisionVertices = null;
        }
Пример #6
0
        // findConstraintPoints
        private void findConstraintPoints(Metamer exclude, Metamer start)
        {
            float minLateralDot = 0.4f;
            int maxLateralConstraints = 8;
            int maxPreviousConstraints = 4;

            // Search previous path
            if (start.previousMetamer != null && start.previousMetamer != exclude)
            {
                Metamer current = start;
                bool done = false;
                while (!done)
                {
                    // Stop searching and spawn a new constraint point search if current.previous is a branching point or tail
                    if (current.previousMetamer != null && (current.previousMetamer.isBranchingPoint()))
                    {
                        done = true;
                        previousConstraintPoints.Add(current.previousMetamer);
                        if (previousConstraintPoints.Count < maxPreviousConstraints)
                            findConstraintPoints(current, current.previousMetamer);
                    }

                    if (!done)
                    {
                        // Continue searching if the previous metamer exists
                        if (current.previousMetamer != null)
                            current = current.previousMetamer;
                        else
                            done = true;
                    }
                }
            }

            // Search main path
            if (start.mainMetamer != null && start.mainMetamer != exclude)
            {
                Metamer current = start;
                bool done = false;
                while (!done)
                {
                    // Stop searching and spawn a new constraint point search if current.main is a branching point or tail
                    if (current.mainMetamer != null && (current.mainMetamer.isBranchingPoint() || current.mainMetamer.isTail))
                    {
                        done = true;
                        Vector2 relative = position - current.mainMetamer.position;
                        relative.Normalize();
                        Vector2 normal = start.position - current.mainMetamer.position;
                        normal.Normalize();
                        if (Math.Abs(Vector2.Dot(relative, normal)) >= minLateralDot)
                            constraintPoints.Add(current.mainMetamer);
                        if (constraintPoints.Count < maxLateralConstraints)
                            findConstraintPoints(current, current.mainMetamer);
                    }

                    if (!done)
                    {
                        // Continue searching if the previous metamer exists
                        if (current.mainMetamer != null)
                            current = current.mainMetamer;
                        else
                            done = true;
                    }
                }
            }

            // Search lateral path
            if (start.lateralMetamer != null && start.lateralMetamer != exclude)
            {
                Metamer current = start;
                bool done = false;
                while (!done)
                {
                    // Stop searching and spawn a new constraint point search if current.main is a branching point or tail
                    if (current.lateralMetamer != null && (current.lateralMetamer.isBranchingPoint() || current.lateralMetamer.isTail))
                    {
                        done = true;
                        Vector2 relative = position - current.lateralMetamer.position;
                        relative.Normalize();
                        Vector2 normal = start.position - current.lateralMetamer.position;
                        normal.Normalize();
                        if (Math.Abs(Vector2.Dot(relative, normal)) >= minLateralDot)
                            constraintPoints.Add(current.lateralMetamer);
                        if (constraintPoints.Count < maxLateralConstraints)
                            findConstraintPoints(current, current.lateralMetamer);
                    }

                    if (!done)
                    {
                        // Continue searching if the previous metamer exists
                        if (current.lateralMetamer != null)
                            current = current.lateralMetamer;
                        else
                            done = true;
                    }
                }
            }
        }
Пример #7
0
        public Metamer(Tree tree, Metamer previousMetamer, BudType activeBud, BudState terminalBudState, BudState lateralBudState, float axis, bool placeBudOnLeft)
        {
            this.tree = tree;
            this.activeBud = activeBud;
            this.previousMetamer = previousMetamer;
            this.terminalBudState = terminalBudState;
            this.lateralBudState = lateralBudState;
            this.axis = axis;
            this.placeBudOnLeft = placeBudOnLeft;

            aabb = new AABB();
            isRoot = previousMetamer == null;
            constraintPoints = new List<Metamer>();
            previousConstraintPoints = new List<Metamer>();
            associatedMarkers = new List<MetamerMarker>();
            fixturesToTest = new Fixture[MAX_FIXTURES_TO_TEST];
            localGridHalfWidth = (int)Math.Floor(tree.perceptionRadius / TreeSystem.PLANT_CELL_SIZE) + 2;
            localGridHalfHeight = (int)Math.Floor(tree.perceptionRadius / TreeSystem.PLANT_CELL_SIZE) + 2;
            currentAngle = axis;
            currentTextureAngle = axis;
            collisionVertices = new Vector2[FarseerPhysics.Settings.MaxPolygonVertices];
            collisionNormals = new Vector2[FarseerPhysics.Settings.MaxPolygonVertices];
            constraints = new List<MetamerConstraint>();
            relatedConstraints = new List<MetamerConstraint>();
            _vertices = new VertexPositionColorTexture[2];

            // Mass
            mass = 1f;
            inverseMass = 1f / mass;

            // Calculate position
            position = (isRoot ? tree.position : previousMetamer.position + new Vector2((float)Math.Cos(axis), (float)Math.Sin(axis)) * tree.internodeLength);
            oldPosition = position;

            // Trunk constraints
            if (!isRoot)
            {
                if (isApex() && tree.iterations < 2)
                {
                    // Create anchor constraints
                    Vector2 relative = position - tree.rootPosition;
                    Vector2 anchorA = tree.rootPosition + tree.anchorNormal * 3f;
                    float distance = (anchorA - position).Length();
                    constraints.Add(new TrunkMetamerConstraint(this, anchorA, distance));

                    Vector2 anchorB = tree.rootPosition + tree.anchorNormal * -3f;
                    distance = (anchorB - position).Length();
                    constraints.Add(new TrunkMetamerConstraint(this, anchorB, distance));
                }

                // Create metamer-metamer links
                if (!previousMetamer.isBroken)
                    internodeConstraint = new DistanceMetamerConstraint(this, previousMetamer, tree.internodeLength * 0.8f, 0.5f);
            }

            // Put this metamer in a cell in the metamer grid
            ci = tree.treeSystem.getPlantGridX(position.X);
            cj = tree.treeSystem.getPlantGridY(position.Y);
            if (!tree.treeSystem.metamerGrid.ContainsKey(tree.levelUid))
            {
                tree.treeSystem.metamerGrid.Add(tree.levelUid, new Dictionary<int, Dictionary<int, List<Metamer>>>());
            }
            if (!tree.treeSystem.metamerGrid[tree.levelUid].ContainsKey(ci))
            {
                tree.treeSystem.metamerGrid[tree.levelUid][ci] = new Dictionary<int, List<Metamer>>();
            }
            if (!tree.treeSystem.metamerGrid[tree.levelUid][ci].ContainsKey(cj))
            {
                tree.treeSystem.metamerGrid[tree.levelUid][ci][cj] = new List<Metamer>();
            }
            tree.treeSystem.metamerGrid[tree.levelUid][ci][cj].Add(this);

            // Destroy markers in the occupied zone
            destroyMarkersInOccupiedZone();

            // Expand level boundary
            tree.treeSystem.levelSystem.expandFallbackBoundary(tree.levelUid, position);

            // Determine z-index
            _z = tree.layerDepth + StasisMathHelper.floatBetween(-0.02f, 0.01f, tree.random);
        }
Пример #8
0
        // Constructor
        public Tree(TreeSystem treeSystem, string levelUid, Texture2D barkTexture, List<List<Texture2D>> leafTextures, XElement data)
        {
            _treeSystem = treeSystem;
            _levelUid = levelUid;
            _leafTextures = leafTextures;
            _barkTexture = barkTexture;
            _angle = Loader.loadFloat(data.Attribute("angle"), 0f);
            _seed = Loader.loadInt(data.Attribute("seed"), 12345);
            _age = Loader.loadFloat(data.Attribute("age"), 0f);
            _internodeHalfLength = Loader.loadFloat(data.Attribute("internode_half_length"), 0.5f);
            _internodeLength = _internodeHalfLength * 2f;
            _maxShootLength = Loader.loadInt(data.Attribute("max_shoot_length"), 4);
            _maxBaseHalfWidth = Loader.loadFloat(data.Attribute("max_base_half_width"), 0.25f);
            _perceptionAngle = Loader.loadFloat(data.Attribute("perception_angle"), 0.6f);
            _perceptionRadius = Loader.loadFloat(data.Attribute("perception_radius"), 4f);
            _occupancyRadius = Loader.loadFloat(data.Attribute("occupancy_radius"), 1f);
            _lateralAngle = Loader.loadFloat(data.Attribute("lateral_angle"), 0.6f);
            _fullExposure = Loader.loadFloat(data.Attribute("full_exposure"), 1f);
            _penumbraA = Loader.loadFloat(data.Attribute("penumbra_a"), 1f);
            _penumbraB = Loader.loadFloat(data.Attribute("penumbra_b"), 2f);
            _optimalGrowthWeight = Loader.loadFloat(data.Attribute("optimal_growth_weight"), 1f);
            _tropismWeight = Loader.loadFloat(data.Attribute("tropism_weight"), 1f);
            _tropism = Loader.loadVector2(data.Attribute("tropism"), Vector2.Zero);
            _position = Loader.loadVector2(data.Attribute("position"), Vector2.Zero);
            _layerDepth = Loader.loadFloat(data.Attribute("layer_depth"), 0.1f);
            _entityId = int.Parse(data.Attribute("id").Value);

            _vertices = new VertexPositionColorTexture[MAX_VERTICES];
            for (int i = 0; i < MAX_VERTICES; i++)
            {
                _vertices[i].Color = Color.White;
            }
            _random = new Random(_seed);
            _internodeLengthSq = _internodeLength * _internodeLength;
            _aabb = new AABB();
            _aabb.LowerBound = _position;
            _aabb.UpperBound = _position;

            // Calculate root position
            float rootAngle = _angle + (StasisMathHelper.pi);
            _rootPosition = _position + new Vector2((float)Math.Cos(rootAngle), (float)Math.Sin(rootAngle)) * 5f;

            // Calculate anchor normals
            float anchorAngle = _angle - (StasisMathHelper.pi * 0.5f);
            _anchorNormal = new Vector2((float)Math.Cos(anchorAngle), (float)Math.Sin(anchorAngle));

            // Create first metamer
            _rootMetamer = new Metamer(this, null, BudType.TERMINAL, BudState.DORMANT, BudState.DEAD, _angle, true);
            _rootMetamer.isTail = true;
        }