public List <IBloxVariable> GetVariablesInBloxScope2(ABlox blox) { List <IBloxVariable> variablesInScope = new List <IBloxVariable>(); RootBlox rootBlox = GetRootBlox(); if (rootBlox != null) { List <BloxIdent> bloxList = rootBlox.GetChildBloxListInVerticalOrder(); //Params are not loaded in GetChildBloxListInVerticalOrder() method, so we evaluate according to the parent index //on that case BloxIdent bloxIdent = bloxList.Find(b => b.blox == (blox.IsParam ? blox.ParentBlox : blox)); BloxIdent bloxIdent2 = bloxList.Where(b => b.blox == (blox.IsParam ? blox.ParentBlox : blox)).FirstOrDefault(); int indexOfBlox = -1; try { indexOfBlox = bloxList.IndexOf(bloxIdent); } catch (Exception ex) { } if (indexOfBlox >= 0) { // Gets all the bloxes above this one, that are variables // Although pure Blox objects cannot be cast as IBloxVariable, // objects of classes that inherit from Blox, and implement IBloxVariable, can variablesInScope = bloxList.GetRange(0, indexOfBlox).Where(b => GameObjectHelper.CanBeCastedAs <IBloxVariable>(b.blox)).Select(b => (IBloxVariable)b.blox).ToList(); } } return(variablesInScope); }
private float GetParamSpacing(RootBlox rootBlox) { BoundingBox2D rootBBox = GameObjectHelper.getBoundingBoxInWorld(rootBlox.gameObject); float rootBloxWidth = GameObjectHelper.getWidthFromBBox(rootBBox); float bloxParamSpacing = rootBloxWidth / 10; return(bloxParamSpacing); }
private float GetVerticalSpacing(RootBlox rootBlox) { BoundingBox2D rootBBox = GameObjectHelper.getBoundingBoxInWorld(rootBlox.gameObject); float rootBloxHeight = GameObjectHelper.getHeightFromBBox(rootBBox); float bloxVerticalSpacing = 2 * rootBloxHeight / 3; return(bloxVerticalSpacing); }
/// <summary> /// What Hint looks for: /// Gets the placed bloxes /// looks at the bloxes that are expected to be placed /// /// looks for the expected patterns: /// Horizontal line /// Vertical line /// Olhar para o que se faz no final de cada padrão: virar à esquerda,ou à direita? /// /// </summary> public void LoadHint(RootBlox rootBlox) { // 1. Check for mandatory bloxes not used List <Tuple <Type, int> > usedBloxTypeCount = rootBlox.GetAllBloxesBellow().GroupBy(b => b.GetType()).Select(g => new Tuple <Type, int>(g.First().GetType(), g.Count())).ToList(); List <ExpectedBlox> mandatoryBloxesNotUsed = LevelConfiguration.MandatoryBloxes.Where(mb => !usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType && b.Item2 >= mb.MinimumQuantity)).ToList(); // 1. Check for optional bloxes not used List <ExpectedBlox> expectedOptionalBloxesNotUsed = LevelConfiguration.OptionalExpectedBloxes.Where(mb => !usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType && b.Item2 >= mb.MinimumQuantity)).ToList(); }
public void SetAllBloxesPositionsOnScreen() { RootBlox rootBlox = GetRootBlox(); if (rootBlox != null) { float bloxVerticalSpacing = GetVerticalSpacing(rootBlox); float identSpacing = GetIdentSpacing(rootBlox); float paramSpacing = GetParamSpacing(rootBlox); SetChildBloxesPositionOnScreen(rootBlox, bloxVerticalSpacing, identSpacing, paramSpacing); } }
public void NestObject(GameObject secondObject) { RootBlox rootBlox = GetRootBlox(); if (rootBlox != null && NestingActive) { if (secondObject.GetComponent <ABlox>() != null && secondObject != null && ValidateNesting(secondObject)) { ABlox secondObjectBlox = secondObject.GetComponent <ABlox>(); Vector2 thisObjectPosition = this.gameObject.transform.position; Vector2 secondObjectPosition = secondObject.transform.position; RectTransform gameObjectTransform = this.gameObject.GetComponent <RectTransform>(); RectTransform collidedObjectTransform = secondObject.GetComponent <RectTransform>(); BoundingBox2D thisBBox = GameObjectHelper.getBoundingBoxInWorld(this.gameObject); BoundingBox2D secondObjBBox = GameObjectHelper.getBoundingBoxInWorld(secondObject); float thisObjectWidth = GameObjectHelper.getWidthFromBBox(thisBBox); float secondObjectWidth = GameObjectHelper.getWidthFromBBox(secondObjBBox); float thisObjectHeight = GameObjectHelper.getHeightFromBBox(thisBBox); float secondObjectHeight = GameObjectHelper.getHeightFromBBox(secondObjBBox); //checks if second object top is bellow this object center if (secondObjBBox.top.y < thisObjectPosition.y) { if (!secondObjectBlox.IsParam && ValidateNestToBottom(secondObject) && MathHelper.IsNearby(secondObjBBox.left.x, thisBBox.left.x, thisObjectWidth / 4)) { AddToBottom(secondObjectBlox); OnNestToBottom(); } else if (!secondObjectBlox.IsParam && ValidateNestToBottomIdented(secondObject) && MathHelper.IsNearby(secondObjBBox.left.x, thisBBox.bottom.x, thisObjectWidth / 4)) { AddToBottomIdented(secondObjectBlox); OnNestToBottomIdented(); } } else //if it is above { // Checks if the left parth of the second object is near the right part of the first, and verifies if they are kind of aligned if (ValidateNestToTheSide(secondObject) && MathHelper.IsNearby(secondObjBBox.left.y, thisBBox.right.y, thisObjectHeight / 4) && MathHelper.IsNearby(secondObjBBox.left.x, thisBBox.right.x, thisObjectWidth / 4)) { // Nest side to side AddParam(secondObjectBlox); OnNestToSide(); } } OnNest(); SetAllBloxesPositionsOnScreen(); } } }
/// <summary> /// Gets all the variable bloxes on the scope of a blox. They are presented in the following order: /// the one closest to blox, to the one closest to root. /// </summary> /// <param name="blox"></param> /// <returns></returns> public List <IBloxVariable> GetVariablesInBloxScope(ABlox blox) { List <IBloxVariable> variablesInScope = new List <IBloxVariable>(); RootBlox rootBlox = GetRootBlox(); if (rootBlox != null) { List <ABlox> bloxesInScope = blox.GetBloxesInScope(blox); variablesInScope = bloxesInScope.Where(b => GameObjectHelper.CanBeCastedAs <IBloxVariable>(b)).Select(b => (IBloxVariable)b).ToList(); } return(variablesInScope); }
public void OnDrag(PointerEventData eventData) { IsBeingDragged = true; bloxTransform.position = eventData.position; // If this blox has child bloxes and params, sets their positions in // order to drag them also RootBlox rootBlox = GetRootBlox(); if (rootBlox != null) { float bloxVerticalSpacing = GetVerticalSpacing(rootBlox); float identSpacing = GetIdentSpacing(rootBlox); float paramSpacing = GetParamSpacing(rootBlox); // Sets the child blox and params position while dragging, for them to follow this blox // Those bloxes nesting is temporarily disabled SetChildBloxesPositionOnScreen(this, bloxVerticalSpacing, identSpacing, paramSpacing, false); } // Verifies if there are collided objects, and if // this object can be potentially nested to those if (collidedObjects.Count > 0) { // Although we are saving all the simultaneous collisions // We only want this object to nest with the highest ones float maxY = collidedObjects.Max(c => c.transform.position.y); List <GameObject> highestObjects = collidedObjects.Where(c => c.transform.position.y == maxY).Select(a => a.gameObject).ToList(); ResetHightlight(); foreach (GameObject collidedObject in highestObjects) { //If the collided object is a blox, checks if this is nestable to it, and hightlights if it is if (GameObjectHelper.HasComponent <ABlox>(collidedObject)) { NestingType nestingType = collidedObject.GetComponent <ABlox>().DetermineNestingType(this.gameObject); if (nestingType != NestingType.NONE && GameObjectHelper.HasComponent <HighlightableButton>(collidedObject.gameObject)) { HighlightableButton hB = collidedObject.gameObject.GetComponent <HighlightableButton>(); hB.HighlightButton(HighlightableButton.ButtonHighlight.Info); hightlightableBloxes.Add(hB); } } } } }
/// <summary> /// Checks if object passed can be nested to this one, and returns nesting type /// </summary> /// <param name="secondObject"></param> /// <returns></returns> public NestingType DetermineNestingType(GameObject secondObject) { NestingType nestingType = NestingType.NONE; RootBlox rootBlox = GetRootBlox(); if (rootBlox != null && NestingActive) { if (secondObject.GetComponent <ABlox>() != null && secondObject != null && ValidateNesting(secondObject)) { ABlox secondObjectBlox = secondObject.GetComponent <ABlox>(); Vector2 thisObjectPosition = this.gameObject.transform.position; BoundingBox2D thisBBox = GameObjectHelper.getBoundingBoxInWorld(this.gameObject); BoundingBox2D secondObjBBox = GameObjectHelper.getBoundingBoxInWorld(secondObject); float thisObjectWidth = GameObjectHelper.getWidthFromBBox(thisBBox); float thisObjectHeight = GameObjectHelper.getHeightFromBBox(thisBBox); //checks if second object top is bellow this object center if (secondObjBBox.top.y < thisObjectPosition.y) { if (!secondObjectBlox.IsParam && ValidateNestToBottom(secondObject) && MathHelper.IsNearby(secondObjBBox.left.x, thisBBox.left.x, thisObjectWidth / 4)) { nestingType = NestingType.BOTTOM; } else if (!secondObjectBlox.IsParam && ValidateNestToBottomIdented(secondObject) && MathHelper.IsNearby(secondObjBBox.left.x, thisBBox.bottom.x, thisObjectWidth / 4)) { nestingType = NestingType.BOTTOM_IDENTED; } } else //if it is above { // Checks if the left parth of the second object is near the right part of the first, and verifies if they are kind of aligned if (ValidateNestToTheSide(secondObject) && MathHelper.IsNearby(secondObjBBox.left.y, thisBBox.right.y, thisObjectHeight / 4) && MathHelper.IsNearby(secondObjBBox.left.x, thisBBox.right.x, thisObjectWidth / 4)) { // Nest side to side nestingType = NestingType.SIDE; } } } } return(nestingType); }
public Evaluation EvaluateLevel(RootBlox rootBlox) { ObjectiveCheck check; int stars = 0; /// Each level will have 5 objectives: /// 1 - Complete in time /// 2 - Use a number of attempts lesser than the maximum /// 3 - Use a number of blocks lesser than the maximum /// 4 - Use the expected optional bloxes /// 5 - Complete the in game objective (mandatory steps, bloxes, special actions) /// // 1. Time evaluation DateTime expectedEndTime = startTime.AddMinutes(LevelConfiguration.MaxTimeInMinutes); check.exceededMinutes = (DateTime.Now - expectedEndTime).TotalMinutes; // 2. Number of attempts check.exceededAttempts = numberOfAttempts - (int)LevelConfiguration.MaxAttempts; check.numberOfAttempts = numberOfAttempts; // 3. Use a number of code lines lesser than the maximum check.exceededLines = rootBlox.GetChildBloxListInVerticalOrder().Count - (int)LevelConfiguration.MaxCodeLinesExpected; check.usedLines = rootBlox.GetChildBloxListInVerticalOrder().Count; // 4. Right steps. This is a mandatory object, so level shall fail when not accomplished // 4.1 Get all the mandatory steps that were executed, with the special action included // The final count should match the count of LevelConfiguration.MandatorySteps //var queryMandatoryStepsCompleted = from mandatoryStep in LevelConfiguration.MandatorySteps // join plotTile in tilesInScene on mandatoryStep.CoordinateInPlot equals plotTile.PlotPosition // where mandatoryStep != null && plotTile != null && plotTile.SpecialActionExecuted == mandatoryStep.SpecialAction && plotTile.Stepped // select plotTile; var queryMandatoryStepsCompleted = LevelConfiguration.MandatorySteps.Where(ms => tilesInScene.Exists(t => t.Stepped && t.SpecialActionExecuted == ms.SpecialAction && t.PlotPosition == ms.CoordinateInPlot)); bool allTheMandatoryStepsDone = queryMandatoryStepsCompleted.Count() == LevelConfiguration.MandatorySteps.Count; // 4.2 Get all the the not expected steps. It is mandatory that the user restricts to the mandatory steps var queryNotExpectedSteps = from plotTile in tilesInScene join mandatoryStep in LevelConfiguration.MandatorySteps on plotTile.PlotPosition equals mandatoryStep.CoordinateInPlot into mSteps from step in mSteps.DefaultIfEmpty() where step == null && plotTile.Stepped select plotTile; bool notExpectedStepsExist = queryNotExpectedSteps.Count() > 0; check.wrongSteps = queryNotExpectedSteps.Count(); check.mandatorySteps = !notExpectedStepsExist && allTheMandatoryStepsDone; // 5. This list contains the distinct blox types, and their count List <Tuple <Type, int> > usedBloxTypeCount = rootBlox.GetAllBloxesBellow().GroupBy(b => b.GetType()).Select(g => new Tuple <Type, int>(g.First().GetType(), g.Count())).ToList(); List <ExpectedBlox> mandatoryBloxesFullyUsed = LevelConfiguration.MandatoryBloxes.Where(mb => usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType && b.Item2 >= mb.MinimumQuantity)).ToList(); check.mandatoryBloxes = mandatoryBloxesFullyUsed.Count == LevelConfiguration.MandatoryBloxes.Count(); List <ExpectedBlox> expectedOptionalBloxesUsed = LevelConfiguration.OptionalExpectedBloxes.Where(mb => usedBloxTypeCount.Exists(b => b.Item1 == mb.BloxType)).ToList(); int numberOfOptionalBloxesUsed = usedBloxTypeCount // Gets all the used bloxes that are of the type of one expected to be used .Where(b => LevelConfiguration.OptionalExpectedBloxes.Exists(mb => mb.BloxType == b.Item1)) // Gets the amount used. If the amount used is bigger than the minimum expected, uses the later value // If it is expected to use 2 bloxes of Int, and 1 of If, we don't want to classify a full use of option bloxes // if the user put 3 Int bloxes .Select(b => Math.Min(b.Item2, LevelConfiguration.OptionalExpectedBloxes.First(o => o.BloxType == b.Item1).MinimumQuantity)).Sum(); check.optionalBloxesUsedPercentage = LevelConfiguration.OptionalExpectedBloxes.Count == 0 ? 1 : numberOfOptionalBloxesUsed * 1f / LevelConfiguration.OptionalExpectedBloxes.Select(o => o.MinimumQuantity).Sum(); check.maxAttemptsExpected = Convert.ToInt32(LevelConfiguration.MaxAttempts); check.maxLinesExpected = Convert.ToInt32(LevelConfiguration.MaxCodeLinesExpected); check.maxMinutesExpected = Convert.ToInt32(LevelConfiguration.MaxTimeInMinutes); check.maxOptionalBloxesExpected = Convert.ToInt32(LevelConfiguration.OptionalExpectedBloxes.Select(o => o.MinimumQuantity).Sum()); check.numberOfOptionalBloxesUsed = numberOfOptionalBloxesUsed; return(new Evaluation(check)); }