//--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- //bot makes a plan of action (determines place to reach) and starts moving private void figureOutWhereToHeadTo() { //resest action lists + variables possibleLeftActions.Clear(); possibleRightActions.Clear(); jumpPlatforms.Clear(); holeSpottedB4 = false; //get x position of closest left and right wall float rightWallLocation = info[new EnvKey('R', 0, 0)].location().x; float leftWallLocation = info[new EnvKey('L', 0, 0)].location().x; //bot takes into account it's last action/location lastAction = action.Equals(null) ? 'A' : action.direction; lastMovement = action.Equals(null) ? 1 : (int)Mathf.Sign(action.x); //the bot looks to its left for 1) openings in the floor it can drop down in 2) seperate platforms it can jump to for (int offset = -1; offset >= -5; offset--) { EnvKey floorCheck = new EnvKey('G', offset, 0); EnvKey prevFloorCheck = new EnvKey('G', offset + 1, 0); //make sure this opening in the floor is not behind a wall (as the bot can't just walk straight to it then) if (info[floorCheck].location().x > leftWallLocation) { //consider going to the first drop down opening on it's left if (info[floorCheck].location().y <= transform.position.y - 3.2f && !holeSpottedB4) { holeSpottedB4 = true; possibleLeftActions.Add(floorCheck); } //consider going to the first seperate platform it can jump to on it's left if (offset != -1 && info[floorCheck].location().y > transform.position.y - 6.5f && info[prevFloorCheck].location().y <= info[floorCheck].location().y - 0.1f && holeSpottedB4) { possibleLeftActions.Add(floorCheck); } } } //reset hole spotted variable holeSpottedB4 = false; //the bot looks to its right for 1) openings in the floor it can drop down in 2) seperate platforms it can jump to for (int offset = 1; offset <= 5; offset++) { EnvKey floorCheck = new EnvKey('G', offset, 0); EnvKey prevFloorCheck = new EnvKey('G', offset - 1, 0); //make sure this opening in the floor is not behind a wall (as the bot can't just walk straight to it then) if (info[floorCheck].location().x < rightWallLocation) { //consider going to the first drop down opening on it's right if (info[floorCheck].location().y <= transform.position.y - 3.2f && !holeSpottedB4) { holeSpottedB4 = true; possibleRightActions.Add(floorCheck); } //consider going to the first seperate platform it can jump to on it's right else if (offset != 1 && info[floorCheck].location().y > transform.position.y - 6.5f && info[prevFloorCheck].location().y <= info[floorCheck].location().y - 0.1f && holeSpottedB4) { possibleRightActions.Add(floorCheck); } } } //if there is a hallway to the right, consider going there if (possibleRightActions.Count <= 1 && rightWallLocation > transform.position.x + 2f) { //bot should usually consider going right (if it wasn't already going left or if it can't go LEFT next turn) if (lastAction != 'L' || leftWallLocation >= transform.position.x - 2.5f) { possibleRightActions.Add(new EnvKey('R', 0, 0)); } //if the bot was previously heading left, it should rarely consider going right else if (lastAction == 'L') { int r = Random.Range(0, 10); if (r >= 9) { possibleRightActions.Add(new EnvKey('R', 0, 0)); } } } //if there is a hallway to the left, still consider going there if (possibleLeftActions.Count <= 1 && leftWallLocation < transform.position.x - 2f) { //bot should usually consider going left (if it wasn't already going right or if it can't go right next turn) if (lastAction != 'R' || rightWallLocation <= transform.position.x + 2.5f) { possibleLeftActions.Add(new EnvKey('L', 0, 0)); } //if the bot was previously heading right, it should rarely consider going left else if (lastAction == 'R') { int r = Random.Range(0, 10); if (r >= 9) { possibleLeftActions.Add(new EnvKey('L', 0, 0)); } } } //the bot checks for openings in the ceiling for (int offset = -5; offset <= 5; offset++) { //get the y coordinate of the ceiling above the player EnvKey ceilingCheck = new EnvKey('C', offset, 0); EnvInfo ceiling = info[ceilingCheck]; //get the expected height a ceiling should be (for a normal ceiling with no opening) float expectedHeight = 4f + transform.position.y; float ceilingHeight = ceiling.location().y; //if there is a gap in the ceiling, and its not behind a left or right wall if (ceilingHeight > expectedHeight && ceiling.location().x < rightWallLocation && ceiling.location().x > leftWallLocation) { //if the bot theoretically jumped through the ceiling gap, calculate how far back the left and right walls are on the new platform they would land on Vector2 rayCastOrigin = new Vector2(transform.position.x + offset * 1.5f, transform.position.y + 4f); RaycastHit2D leftHit = Physics2D.Raycast(rayCastOrigin, Vector2.left, 9f, Constants.map); RaycastHit2D rightHit = Physics2D.Raycast(rayCastOrigin, Vector2.right, 9f, Constants.map); float leftUpperWall = (leftHit.collider != null) ? leftHit.point.x : rayCastOrigin.x - 9; float rightUpperWall = (rightHit.collider != null) ? rightHit.point.x : rayCastOrigin.x + 9; float rightUpperWallDistance = rightUpperWall - rayCastOrigin.x; float leftUpperWallDistance = rayCastOrigin.x - leftUpperWall; //setting these variables to miscellaneous values to avoid null errors EnvInfo leftCeiling = info[new EnvKey('C', 0, 0)]; EnvInfo rightCeiling = info[new EnvKey('C', 0, 0)]; float leftCeilingHeight = 0, rightCeilingHeight = 0; GameObject leftCeilingObject = null, rightCeilingObject = null; //can't do left ceiling checks for the left most ceiling and vice versa on the right side if (offset != -5) { leftCeiling = info[new EnvKey('C', offset - 1, 0)]; leftCeilingHeight = leftCeiling.location().y; leftCeilingObject = leftCeiling.gameObject(); } if (offset != 5) { rightCeiling = info[new EnvKey('C', offset + 1, 0)]; rightCeilingHeight = rightCeiling.location().y; rightCeilingObject = rightCeiling.gameObject(); } GameObject groundObject = info[new EnvKey('G', 0, 0)].gameObject(); //get the tilt of the walls directly to the left and right of the bot right now EnvInfo rightWall = info[new EnvKey('R', 0, 0)]; float rightWallTilt = rightWall.gameObject() ? rightWall.gameObject().transform.eulerAngles.z : 0f; EnvInfo leftWall = info[new EnvKey('L', 0, 0)]; float leftWallTilt = leftWall.gameObject() ? leftWall.gameObject().transform.eulerAngles.z : 0f; //if bot spots an opening in the ceiling to its left or right and there is ceiling directly to the right of the opening, //then add this jump as a possible action as long as there is no nearby ramp to the right if (offset != 5 && rightCeilingHeight < expectedHeight && rightUpperWallDistance > 2f && rightCeilingObject != groundObject && (!rightWall.gameObject() || Mathf.Abs(rightCeiling.location().x - rightWall.location().x) > 1.51f || !wallIsActuallyARamp(rightWallTilt))) { if (offset > 0) { possibleRightActions.Add(ceilingCheck); } else if (offset < 0) { possibleLeftActions.Add(ceilingCheck); } else if (offset == 0) { if (ceiling.location().x >= transform.position.x) { possibleRightActions.Add(ceilingCheck); } else { possibleLeftActions.Add(ceilingCheck); } } jumpPlatforms.Add(ceilingCheck, "right"); jumpToHeight = transform.position.y + 4f; } //if bot spots an opening in the ceiling to its left or right, but there is ceiling directly to the left of the opening in the ceiling, then add this jump as a possible action else if (offset != -5 && leftCeilingHeight < expectedHeight && leftUpperWallDistance > 2f && leftCeilingObject != groundObject && (!leftWall.gameObject() || Mathf.Abs(leftCeiling.location().x - leftWall.location().x) > 1.51f || !wallIsActuallyARamp(leftWallTilt))) { if (offset > 0) { possibleRightActions.Add(ceilingCheck); } else if (offset < 0) { possibleLeftActions.Add(ceilingCheck); } else if (offset == 0) { if (ceiling.location().x <= transform.position.x) { possibleLeftActions.Add(ceilingCheck); } else { possibleRightActions.Add(ceilingCheck); } } jumpPlatforms.Add(ceilingCheck, "left"); jumpToHeight = transform.position.y + 4f; } } } //bot chooses where to head to action = pickPossibleAction(); endSpot = info[action].location(); action.printColored(); //bot heads to the place it chose if (action.direction == 'G') { check = 1; dir = Mathf.Sign(action.x); } else if (action.direction == 'R') { check = 201; dir = 1; } else if (action.direction == 'L') { check = 201; dir = -1; } else if (action.direction == 'C') { dir = Mathf.Sign(action.x); check = 301; } rig.velocity = new Vector2(botSpeed * dir, rig.velocity.y); actionsTakenToExecutePath(); }
//--------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- //bot randomly chooses to go left or right, then picks a destination to their left or right private EnvKey pickPossibleAction() { foreach (EnvKey key in possibleLeftActions) { Debug.LogFormat("Left| {0}: {1}, {2}", key.direction, key.x, key.y); } foreach (EnvKey key in possibleRightActions) { Debug.LogFormat("Right| {0}: {1}, {2}", key.direction, key.x, key.y); } //bot randomly picks a direction, but gives greater weight to moving in the same direction as before int chooseDirection = Random.Range(0, 100); chooseDirection = (lastMovement == -1) ? (chooseDirection - 20) : chooseDirection + 20; //if the bot is on a ramp, it recalculates its decision super often, so make it super inclined to continue int he same direction EnvInfo ground = info[new EnvKey('G', 0, 0)]; float groundTilt = (ground.gameObject()) ? ground.gameObject().transform.localEulerAngles.z : 0; if (ground.gameObject() && transform.position.y - ground.location().y < 1.6f && groundIsRamp(groundTilt)) { chooseDirection += 40 * lastMovement; //Debug.Log("on ramp"); } // else // Debug.Log("off ramp " + ground + ", " + (transform.position.y - ground.location().y) + ", " + groundIsRamp(groundTilt)); //sometimes the bot MUST go left or MUST go right if (possibleLeftActions.Count == 0) { chooseDirection = 50; } else if (possibleRightActions.Count == 0) { chooseDirection = 0; } //for debugging purposes if (testSpecificAction) { return(testKey); } Debug.Log(chooseDirection + ", " + lastMovement); //pick a left or right destination if (chooseDirection < 50 && possibleLeftActions.Count > 0) { int choice = Random.Range(0, possibleLeftActions.Count); return(possibleLeftActions[choice]); } else if (chooseDirection >= 50 && possibleRightActions.Count > 0) { int choice = Random.Range(0, possibleRightActions.Count); return(possibleRightActions[choice]); } //if the bot somehow has no left/right paths it found (should be impossible), pick a random direction else { Debug.LogError("both action lists were empty :("); int r = Random.Range(0, 10); char dir = (r <= 4) ? 'R' : 'L'; return(new EnvKey(dir, 0, 0)); } }