public static void create(long key, WayReference endPoint, string materialId) { bool isNode1 = endPoint.isNode1(NodeIndex.getPosById(key)); bool isSmall = endPoint.SmallWay; Vector3 originalScale = endPoint.gameObject.transform.localScale; Vector3 nodeCameraPos = Game.getCameraPosition(isNode1 ? endPoint.node1 : endPoint.node2); Vector3 fromPos = nodeCameraPos - new Vector3(0f, originalScale.y / 2f, 0f); Vector3 toPos = fromPos + new Vector3((isSmall ? originalScale.x / 2f : originalScale.y / 2f), originalScale.y, 0f); GameObject endPointObj = MapSurface.createPlaneMeshForPoints(fromPos, toPos, MapSurface.Anchor.LEFT_CENTER); endPointObj.name = "End of way (" + key + ")"; Vector3 zOffset = new Vector3(0, 0, Game.WAYS_Z_POSITION); endPointObj.transform.position = endPointObj.transform.position + zOffset - (isNode1 ? Vector3.zero : endPoint.transform.rotation * new Vector3(isSmall ? originalScale.x / 2f : originalScale.y / 2f, 0f, 0f)); endPointObj.transform.parent = Game.instance.waysParent; endPointObj.transform.rotation = endPoint.transform.rotation; AutomaticMaterialObject endPointMaterialObject = endPointObj.AddComponent <AutomaticMaterialObject> () as AutomaticMaterialObject; endPointMaterialObject.requestMaterial(materialId, null); // TODO - Default material // Add rigidbody and mesh collider, so that they will fall onto the underlying plane Misc.AddGravityToWay(endPointObj); Misc.AddWayObjectComponent(endPointObj); }
public static void CreateCurved(GameObject parent, long key, List <WayReference> wayReferences) { // Make sure to only make dashed lines if the number of fields are the same in the way direction WayReference firstWayReference = wayReferences [0]; WayReference secondWayReference = wayReferences [1]; bool firstIsNode1 = firstWayReference.isNode1(NodeIndex.getPosById(key)); bool secondIsNode1 = secondWayReference.isNode1(NodeIndex.getPosById(key)); float firstFieldsTowardsPos = firstWayReference.getNumberOfFieldsInDirection(!firstIsNode1); float secondFieldsFromPos = secondWayReference.getNumberOfFieldsInDirection(secondIsNode1); float secondFieldsTowardsPos = secondWayReference.getNumberOfFieldsInDirection(!secondIsNode1); float firstFieldsFromPos = firstWayReference.getNumberOfFieldsInDirection(firstIsNode1); bool makeDashedLines = firstFieldsTowardsPos == secondFieldsFromPos && secondFieldsTowardsPos == firstFieldsFromPos; if (firstWayReference.way.WayWidthFactor >= WayHelper.LIMIT_WAYWIDTH && firstWayReference.way.CarWay) { // createOuterLines (reference); CreateCurvedMiddleLine(parent, key, wayReferences); if (makeDashedLines) { CreateCurvedDashedLines(parent, key, wayReferences); } } }
public static void Create(GameObject parent, long key, List <WayReference> wayReferences) { WayReference firstWayReference = wayReferences[0]; WayReference secondWayReference = wayReferences[1]; Quaternion firstWayRotation = firstWayReference.transform.rotation; float crossingAngle = (secondWayReference.transform.rotation.eulerAngles.z - firstWayRotation.eulerAngles.z) / 2f; Vector3 crossingRotationVector = new Vector3(0f, 0f, firstWayRotation.eulerAngles.z + crossingAngle); Quaternion crossingRotation = Quaternion.Euler(crossingRotationVector); Quaternion orthoCrossingRotation = Quaternion.Euler(crossingRotationVector + WayHelper.DEGREES_90_VECTOR); Pos pos = NodeIndex.getPosById(key); GameObject crossingLine = Game.instance.wayCrossing; float lineHeight = crossingLine.transform.localScale.y; float wayScale = Game.instance.partOfWay.transform.localScale.y * Settings.wayWidthFactor; float lineWidth = crossingLine.transform.localScale.x * Settings.wayWidthFactor * firstWayReference.way.WayWidthFactor; float wayHeight = firstWayReference.way.WayWidthFactor * wayScale; Vector3 startPosition = Game.getCameraPosition(pos) - orthoCrossingRotation * new Vector3(wayHeight / 2f, 0, 0) + crossingLine.transform.position; float numberOfCrossingLines = Mathf.Floor((wayHeight - WayHelper.CROSSING_LINE_PERCENTAGE * lineHeight) / (lineHeight + WayHelper.CROSSING_LINE_PERCENTAGE * lineHeight)); float spaceHeight = (wayHeight - numberOfCrossingLines * lineHeight) / (numberOfCrossingLines + 1); float stepLength = spaceHeight + lineHeight; for (int i = 1; i <= numberOfCrossingLines; i++) { Vector3 lineCenter = startPosition + orthoCrossingRotation * new Vector3(i * stepLength - lineHeight / 2f, 0, -0.01f); GameObject line = MonoBehaviour.Instantiate(crossingLine, lineCenter, crossingRotation) as GameObject; line.transform.localScale = new Vector3(lineWidth, crossingLine.transform.localScale.y, crossingLine.transform.localScale.z); line.transform.SetParent(parent.transform); } }
private void spawnUnit(EMERGENCY_TYPE type, Vector3 targetPosition) { List <Pos> endPositions = getEndPosForVector(targetPosition); Pos startPos; do { startPos = NodeIndex.getPosById(Misc.pickRandomKey(NodeIndex.endPointDriveWayIndex)); } while (startPos.Id == endPositions[0].Id || (endPositions.Count == 2 && startPos.Id == endPositions[1].Id)); // Find out which is the closest of the two end points Pos endPos = null; Pos secondLastPos = null; if (endPositions.Count == 1) { endPos = endPositions[0]; } else { if (Game.isPathToFirstClosest(startPos, endPositions[0], endPositions[1])) { endPos = endPositions[1]; secondLastPos = endPositions[0]; } else { endPos = endPositions[0]; secondLastPos = endPositions[1]; } } // TODO - When having Ambulance or Fire Truck, change some of these // TODO - Which of these SHOULD be "Po-liz", and which shouldn't float speedFactor = Misc.randomRange(1.1f, 1.5f); float acceleration = Misc.randomRange(3f, 3.5f); long newId = 0L; string newName = "Po-liz"; float newTime = GameTimer.elapsedTime() + Misc.randomRange(5f, 15f); List <long> newWayPoints = secondLastPos != null ? new List <long>() { secondLastPos.Id } : new List <long>(); string newBrand = "Po-liz"; string newType = "Po-liz"; List <long> newPassengerIds = new List <long>(); List <float> newMood = new List <float>() { 1f, 0f, 1.5f }; Setup.VehicleSetup vehicleSetup = new Setup.VehicleSetup(newId, newName, newTime, startPos.Id, endPos.Id, null, false, false, newWayPoints, newBrand, null, newType, 0, 0F, 1F, 0L, newPassengerIds, speedFactor, acceleration, 0F, 0F, 0f, null, null, newMood, 0.1F, 0.05F, true, true); vehicleSetup.emergencyId = emergencyId; CustomObjectCreator.instance.addVehicle(vehicleSetup); }
private void setWaypointsInfo(Setup.PersonSetup personality) { if (personality != null && personality.wayPoints != null) { this.wayPoints = NodeIndex.getPosById(personality.wayPoints); this.wayPointsLoop = personality.wayPointsLoop; } else { this.wayPoints = new List <Pos>(); } }
private static void CreateTrafficLightColliders() { // For each pos in TrafficLightsForPos, register an entry in TrafficLightToggle, with position and radius foreach (KeyValuePair <long, List <TrafficLightLogic> > trafficLightGroup in TrafficLightsForPos) { long posId = trafficLightGroup.Key; Pos centerPos = NodeIndex.getPosById(posId); float maxDistance = 0f; Vector3 centerPosCameraPosition = Game.getCameraPosition(centerPos); // Get max distance from crossing foreach (TrafficLightLogic trafficLight in trafficLightGroup.Value) { maxDistance = Mathf.Max(Vector2.Distance(trafficLight.transform.position, centerPosCameraPosition), maxDistance); } // Double the maxDistance to get a somewhat bigger touch area TrafficLightToggle.Add(posId, centerPosCameraPosition, maxDistance * 2f); } TrafficLightToggle.Start(); }
private void grabOrSpawn(int numberOfUnits, EMERGENCY_TYPE type, Vector3 closestToPosition, Vehicle potentialVehicle) { // TODO - Based on "type" string brand = "Po-liz"; List <Vehicle> availableEmergencyUnits = Misc.GetVehicles(brand); // If position is not on map... pretend it's on of our endpoints if (closestToPosition == Misc.VECTOR3_NULL) { long endPointNode = Misc.pickRandomKey(NodeIndex.endPointDriveWayIndex); if (endPointNode != 0L) { closestToPosition = Game.getCameraPosition(NodeIndex.getPosById(endPointNode)); } } else { // Make a collider, this will grow once emergency vehicles are standing still - when dispatching vehicle sees this, it has arrived BoxCollider collider = createCollider(closestToPosition, potentialVehicle); registerCollider(emergencyId, collider); } // Filter the units that are already on the way to other emergencies - and can re-route to given position availableEmergencyUnits = availableEmergencyUnits.FindAll(vehicle => !vehicle.areSirensOn() && vehicle.canReroute(closestToPosition)); // If there are too many, pick out some, either by position, or randomly... if (availableEmergencyUnits.Count > numberOfUnits) { availableEmergencyUnits = pickUnits(numberOfUnits, closestToPosition, availableEmergencyUnits); } // Dispatch units on map dispatchUnits(availableEmergencyUnits, closestToPosition); // If there aren't units on the map, spawn "the rest" spawnUnits(numberOfUnits - availableEmergencyUnits.Count, type, closestToPosition); // Debug.Log(availableEmergencyUnits.Count); }
private List <Pos> getEndPosForVector(Vector3 vector) { // First check in the end-point register foreach (KeyValuePair <long, List <WayReference> > pair in NodeIndex.endPointDriveWayIndex) { if (Game.getCameraPosition(NodeIndex.getPosById(pair.Key)) == vector) { return(new List <Pos>() { NodeIndex.getPosById(pair.Key) }); } } // If not found as end-point, get closest WayReference WayReference closestWayReference = NodeIndex.getClosestWayReference(vector); return(new List <Pos>() { closestWayReference.node1, closestWayReference.node2 }); }
public static void create(long key, List <WayReference> wayReferences, string materialId) { if (off) { return; } Pos pos = NodeIndex.getPosById(key); // Sort based on rotation in the point closest to the intersection wayReferences.Sort(delegate(WayReference x, WayReference y) { float angleDiff = AngleAroundNode(pos, x) - AngleAroundNode(pos, y); // Ignoring float to int issues (if there are any) int angleDiffInt = (int)angleDiff; return(angleDiffInt); }); // Gather our way bounds (used for checking if ways intersects each other) List <Bounds> wayBounds = getWayBounds(wayReferences); // List of positions where to draw the mesh List <Vector3> meshPoints; List <WayReference> intersectionList = Misc.CloneBaseNodeList(wayReferences); bool isComplex = false; if (intersectionList.Count == 2 && wayBounds [0].Intersects(wayBounds [1])) { // Only two ways and they intersect, special logic meshPoints = getMeshPointsForComplexTwoWay(intersectionList, wayBounds, pos); isComplex = true; } else { meshPoints = getMeshPointsForNonComplex(intersectionList, wayBounds, pos); } // Debug.Log ("Intersection"); GameObject intersectionObj = MapSurface.createPlaneMeshForPoints(meshPoints); intersectionObj.name = "Intersection " + (isComplex ? "complex " : "") + (intersectionList.Count - 1) + "-way (" + key + ")"; Vector3 zOffset = new Vector3(0, 0, Game.WAYS_Z_POSITION); intersectionObj.transform.position = intersectionObj.transform.position + zOffset; intersectionObj.transform.parent = Game.instance.waysParent; AutomaticMaterialObject intersectionMaterialObject = intersectionObj.AddComponent <AutomaticMaterialObject> () as AutomaticMaterialObject; intersectionMaterialObject.requestMaterial(materialId, null); // TODO - Should have same material as connecting way(s) Misc.AddGravityToWay(intersectionObj); Misc.AddWayObjectComponent(intersectionObj); // Need waylines for all straight ways if (wayReferences.Count == 2) { bool wayQualifiedForCrossing = wayReferences[0].way.WayWidthFactor >= WayHelper.LIMIT_WAYWIDTH && wayReferences[0].way.CarWay; if (pos.getTagValue("highway") == "crossing" && wayQualifiedForCrossing) { WayCrossing.Create(intersectionObj, key, wayReferences); } else { WayLine.CreateCurved(intersectionObj, key, wayReferences); } } }
private static void CreateCurvedDashedLines(GameObject parent, long key, List <WayReference> wayReferences) { GameObject curveDashedLines = new GameObject(); curveDashedLines.name = "Curved dashed lines"; curveDashedLines.transform.SetParent(parent.transform); curveDashedLines.transform.localPosition = Vector3.zero; Pos centerPos = NodeIndex.getPosById(key); Vector3 posPosition = Game.getCameraPosition(centerPos); WayReference firstReference = wayReferences [0]; WayReference secondReference = wayReferences [1]; bool firstIsNode1 = firstReference.isNode1(centerPos); bool secondIsNode1 = secondReference.isNode1(centerPos); GameObject wayFirst = firstReference.gameObject; GameObject waySecond = secondReference.gameObject; // Number of fields in opposite direction float fieldsFromPos2 = firstReference.getNumberOfFieldsInDirection(false); // Number of fields in own direction float fieldsFromPos1 = firstReference.getNumberOfFieldsInDirection(true); // Number of fields in total float numberOfFields = firstReference.getNumberOfFields(); List <float> dashedLineFields = new List <float> (); for (float field = 1; field < fieldsFromPos2; field++) { dashedLineFields.Add(field); } for (float field = 1; field < fieldsFromPos1; field++) { dashedLineFields.Add(fieldsFromPos2 + field); } // If ways have same "isNode1", invert y-axis for second way bool isSameNode1 = firstIsNode1 == secondIsNode1; // Way width float wayHeight = wayFirst.transform.localScale.y; float wayHeightCompensated = wayHeight - GetLineHeight() * 2f; foreach (float field in dashedLineFields) { GameObject curveDashes = new GameObject(); curveDashes.name = "Curved dashes"; curveDashes.transform.SetParent(curveDashedLines.transform); curveDashes.transform.localPosition = Vector3.zero; // Percentual position of way width, where to put middle line float percentualPositionY = field / numberOfFields; // Get our points (center in y-axis) float yPositionInWay = percentualPositionY * wayHeightCompensated; float dashYMiddle = -wayHeightCompensated / 2f + GetLineHeight() + yPositionInWay - GetDashedLineHeight() / 2f; float dashYMiddleSameNode1 = wayHeightCompensated / 2f - yPositionInWay + GetDashedLineHeight() / 2f; Vector3 firstPosMiddle = posPosition + wayFirst.transform.rotation * new Vector3((firstIsNode1 ? 1 : -1) * wayHeight / 2f, dashYMiddle, 0); Vector3 secondPosMiddle = posPosition + waySecond.transform.rotation * new Vector3((secondIsNode1 ? 1 : -1) * wayHeight / 2f, isSameNode1 ? dashYMiddleSameNode1 : dashYMiddle, 0); Vector3 halfDashedLineHeight = new Vector3(0, GetDashedLineHeight() / 2f, 0); // Get our points (top in y-axis) Vector3 wayFirstHalfDashedHeight = wayFirst.transform.rotation * halfDashedLineHeight; Vector3 waySecondHalfDashedHeight = waySecond.transform.rotation * halfDashedLineHeight; Vector3 firstPosTop = firstPosMiddle - wayFirstHalfDashedHeight; Vector3 secondPosTop = secondPosMiddle + (isSameNode1 ? 1 : -1) * waySecondHalfDashedHeight; // Get our points (bottom in y-axis) Vector3 firstPosBottom = firstPosMiddle + wayFirstHalfDashedHeight; Vector3 secondPosBottom = secondPosMiddle + (isSameNode1 ? -1 : 1) * waySecondHalfDashedHeight; Quaternion firstRotation = firstIsNode1 ? WayHelper.ONEEIGHTY_DEGREES * wayFirst.transform.rotation : wayFirst.transform.rotation; Quaternion secondRotation = secondIsNode1 ? WayHelper.ONEEIGHTY_DEGREES * waySecond.transform.rotation : waySecond.transform.rotation; Vector3 firstDirection = firstRotation * Vector3.right; Vector3 secondDirection = secondRotation * Vector3.right; Vector3 intersectionPoint; Vector3 intersectionPointTop; Vector3 intersectionPointBottom; bool intersectionFound = Math3d.LineLineIntersection(out intersectionPoint, firstPosMiddle, firstDirection, secondPosMiddle, secondDirection); if (!intersectionFound && firstRotation.eulerAngles.z == secondRotation.eulerAngles.z) { intersectionFound = true; intersectionPoint = firstPosMiddle + ((secondPosMiddle - firstPosMiddle) / 2); intersectionPointTop = firstPosTop + ((secondPosTop - firstPosTop) / 2); intersectionPointBottom = firstPosBottom + ((secondPosBottom - firstPosBottom) / 2); } else { Math3d.LineLineIntersection(out intersectionPointTop, firstPosTop, firstDirection, secondPosTop, secondDirection); Math3d.LineLineIntersection(out intersectionPointBottom, firstPosBottom, firstDirection, secondPosBottom, secondDirection); } // TODO - Shouldn't be needed - debug only if (!intersectionFound) { Debug.Log("ERR: " + key); return; } // 1. Get bezier length for curve float bezierLength = Math3d.GetBezierLength(firstPosMiddle, intersectionPoint, secondPosMiddle); // 2. Decide how many dashes to fit, with gaps (also calculate each dash and gap length) // If only one line float numberOfLines = 1f; float dashedLineWidth = bezierLength; float dashedLineGap = 0f; // If more lines if (bezierLength > DASHED_LINE_WIDTH + CITY_DASHED_LINE_GAP) { float totalWidth = 0f; for (numberOfLines = 2f; ; numberOfLines++) { totalWidth = DASHED_LINE_WIDTH + (DASHED_LINE_WIDTH + CITY_DASHED_LINE_GAP) * (numberOfLines - 1); if (totalWidth >= bezierLength) { break; } } dashedLineWidth = DASHED_LINE_WIDTH * bezierLength / totalWidth; dashedLineGap = CITY_DASHED_LINE_GAP * bezierLength / totalWidth; } // 3. Calculate each dash along the line t (time) on bezier curve List <KeyValuePair <float, float> > dashTimes = new List <KeyValuePair <float, float> > (); if (numberOfLines == 1f) { dashTimes.Add(new KeyValuePair <float, float>(0f, 1f)); } else { dashTimes.Add(new KeyValuePair <float, float>(0f, dashedLineWidth / bezierLength)); for (float lineStart = dashedLineWidth + dashedLineGap; lineStart < bezierLength; lineStart += dashedLineWidth + dashedLineGap) { float lineStartTime = lineStart / bezierLength; dashTimes.Add(new KeyValuePair <float, float>(lineStartTime, lineStartTime + dashedLineWidth / bezierLength)); } } foreach (KeyValuePair <float, float> dashTime in dashTimes) { float startTime = dashTime.Key; float endTime = dashTime.Value; float dashLengthPercent = endTime - startTime; float numberOfPoints = Mathf.Max(bezierLength / dashLengthPercent * WayHelper.BEZIER_RESOLUTION, 4f); float eachPointTime = dashLengthPercent / numberOfPoints; List <Vector3> dashPoints = new List <Vector3>(); // Top line for (float t = startTime; t <= endTime; t += eachPointTime) { dashPoints.Add(Math3d.GetVectorInBezierAtTime(t, firstPosTop, intersectionPointTop, secondPosTop)); } // Bottom line for (float t = endTime; t >= startTime; t -= eachPointTime) { dashPoints.Add(Math3d.GetVectorInBezierAtTime(t, firstPosBottom, intersectionPointBottom, secondPosBottom)); } GameObject lineMiddle = MapSurface.createPlaneMeshForPoints(dashPoints); lineMiddle.name = "Curved dash"; WayLine.SetWhiteMaterial(lineMiddle); lineMiddle.transform.SetParent(curveDashes.transform); lineMiddle.transform.localPosition = new Vector3(0, 0, -0.01f); } } }
private static void CreateCurvedMiddleLine(GameObject parent, long key, List <WayReference> wayReferences) { Pos centerPos = NodeIndex.getPosById(key); Vector3 posPosition = Game.getCameraPosition(centerPos); WayReference firstReference = wayReferences [0]; WayReference secondReference = wayReferences [1]; bool firstIsNode1 = firstReference.isNode1(centerPos); bool secondIsNode1 = secondReference.isNode1(centerPos); GameObject wayFirst = firstReference.gameObject; GameObject waySecond = secondReference.gameObject; // Number of fields in opposite direction float fieldsFromPos2 = firstReference.getNumberOfFieldsInDirection(false); // Number of fields in total float numberOfFields = firstReference.getNumberOfFields(); // Percentual position of way width, where to put middle line float percentualPositionY = fieldsFromPos2 / numberOfFields; // Way width float wayHeight = wayFirst.transform.localScale.y - GetLineHeight() * 2f; // TODO - What if the wayReference is REALLY short Vector3 wayFirstSize = wayFirst.transform.localScale; Quaternion wayFirstRotation = wayFirst.transform.rotation; float wayFirstWayWidth = (firstIsNode1 ? 1 : -1) * wayFirstSize.y; float lineFirstPositionAdjustment = percentualPositionY * wayHeight; Vector3 wayFirstMiddleLineTopPos = posPosition + wayFirstRotation * new Vector3(wayFirstWayWidth / 2f, -wayHeight / 2f + lineFirstPositionAdjustment, 0f); Vector3 wayFirstMiddleLineBottomPos = posPosition + wayFirstRotation * new Vector3(wayFirstWayWidth / 2f, -wayHeight / 2f + GetLineHeight() + lineFirstPositionAdjustment, 0f); Vector3 waySecondSize = waySecond.transform.localScale; Quaternion waySecondRotation = waySecond.transform.rotation; float waySecondWayWidth = (secondIsNode1 ? 1 : -1) * waySecondSize.y; float lineSecondPositionAdjustment = percentualPositionY * wayHeight; Vector3 waySecondMiddleLineTopPos = posPosition + waySecondRotation * new Vector3(waySecondWayWidth / 2f, -wayHeight / 2f + lineSecondPositionAdjustment, 0f); Vector3 waySecondMiddleLineBottomPos = posPosition + waySecondRotation * new Vector3(waySecondWayWidth / 2f, -wayHeight / 2f + GetLineHeight() + lineSecondPositionAdjustment, 0f); if (IsTopAndBottomCrossing(wayFirstMiddleLineTopPos, waySecondMiddleLineTopPos, wayFirstMiddleLineBottomPos, waySecondMiddleLineBottomPos)) { Vector3 tmp = wayFirstMiddleLineBottomPos; wayFirstMiddleLineBottomPos = wayFirstMiddleLineTopPos; wayFirstMiddleLineTopPos = tmp; } // DebugFn.square (wayFirstMiddleLineTopPos); // DebugFn.square (wayFirstMiddleLineBottomPos); // DebugFn.square (waySecondMiddleLineTopPos); // DebugFn.square (waySecondMiddleLineBottomPos); List <Vector3> linePoints = new List <Vector3> (); linePoints.Add(wayFirstMiddleLineTopPos); AddBezierPoints(linePoints, wayFirstMiddleLineTopPos, wayFirstRotation, waySecondMiddleLineTopPos, waySecondRotation); linePoints.Add(waySecondMiddleLineBottomPos); AddBezierPoints(linePoints, waySecondMiddleLineBottomPos, waySecondRotation, wayFirstMiddleLineBottomPos, wayFirstRotation); GameObject lineMiddle = MapSurface.createPlaneMeshForPoints(linePoints); lineMiddle.name = "Curved middle line"; WayLine.SetWhiteMaterial(lineMiddle); lineMiddle.transform.SetParent(parent.transform); lineMiddle.transform.localPosition = new Vector3(0, 0, -0.01f); }