Exemple #1
0
    def update(self):
        self.image.set_colorkey(BLACK)

        m1, m2, m3 = pg.mouse.get_pressed()
        self.rect = self.original_rect
        self.image = self.original_image
        if self.bullet_group != None:
            self.bullet_group.update()

        self.rect.y = self.player.rect.y - (self.height /
                                            2) + (self.player.height / 2)

        self.cent_x, self.cent_y = self.player.rect.x + self.player.width / 2, self.player.rect.y + self.player.height / 2

        #Pythag Theorm
        side1_length = math.sqrt((self.cent_x - self.mx)**2 + (
            (self.cent_y + self.player.height / 2) - self.my)**2)
        side2_length = self.player.height / 2
        side3_length = math.sqrt((self.cent_x - self.mx)**2 +
                                 (self.cent_y - self.my)**2)
        #Law of cos, and pythag theorm to find angle of mouse
        self.deg_rotate = math.degrees(
            math.acos(((side2_length**2) + (side3_length**2) -
                       (side1_length**2)) / (2 * side2_length * side3_length)))

        if self.mx <= self.player.rect.x + (self.player.width / 2):
            self.deg_rotate *= -1
            self.pivot_side = -1
            self.rect.x = self.player.rect.x - (self.width / 2) + 10
            self.pivot = self.player.width
        if self.mx >= self.player.rect.x + (self.player.width / 2):
            self.pivot_side = 1
            self.rect.x = self.player.rect.x - (self.width /
                                                2) + (self.player.width) - 10
            self.pivot = self.player.width
            self.image = pg.transform.flip(self.image, True, False)

        self.pivot_offset = pg.math.Vector2(
            0, self.pivot).rotate(-self.deg_rotate)

        self.rotated_image = pg.transform.rotate(
            self.image, self.deg_rotate).convert_alpha()
        self.rotated_rect = self.rotated_image.get_rect(
            center=self.rect.center + self.pivot_offset)

        self.image = self.rotated_image
        self.rect = self.rotated_rect

        if m1 == 0:
            self.shooting = False

        if self.shooting == False and m1 == 1:
            self.shooting = True
            self.shoot()

        if self.player.enemies_killed == self.next_upgrade:
            self.spread_shot += 1
            self.next_upgrade *= 2
    def update(self):
        self.image = pg.transform.scale(
            self.follow.game.spritesheet.get_image(5, 318, 243, 303),
            (60, 80)).convert_alpha()
        self.image.set_colorkey(BLACK)
        # Delete the object if all health is lost
        if self.health <= 0:
            self.kill()
        #Pythag to find distance from player
        self.c = math.sqrt((self.follow.rect.x - self.rect.x)**2 +
                           (self.follow.rect.y - self.rect.y)**2)

        if self.c != 0:
            #Create a multiplier from the distance between the player
            self.x = (self.follow.rect.x - self.rect.x) / self.c
            self.y = (self.follow.rect.y - self.rect.y) / self.c

        #use multiplier to effect speed
        self.rect.x += self.x * self.speed
        self.rect.y += self.y * self.speed

        bullet_collisions = pg.sprite.spritecollide(self, self.bulletgroup,
                                                    True)
        #If there is bullet from the player colliding with the enemy, it will add it to the group, and if there is anything in this group, remove health
        if bullet_collisions:
            self.health -= self.follow.weapon.damage
        self.weapon.update()
Exemple #3
0
    def update(self):
        self.mx, self.my = self.user.follow.rect.x, self.user.follow.rect.y
        m1, m2, m3 = pg.mouse.get_pressed()
        if self.bullet_group != None:
            self.bullet_group.update()

        self.rect.y = self.user.rect.y - (self.height /
                                          2) + (self.user.height / 2)

        self.cent_x, self.cent_y = self.user.rect.x + self.user.width / 2, self.user.rect.y + self.user.height / 2

        #Pythag Theorm
        side1_length = math.sqrt((self.cent_x - self.mx)**2 + (
            (self.cent_y + self.user.height / 2) - self.my)**2)
        side2_length = self.user.height / 2
        side3_length = math.sqrt((self.cent_x - self.mx)**2 +
                                 (self.cent_y - self.my)**2)
        #Law of cos, and pythag theorm to find angle of mouse
        self.deg_rotate = math.degrees(
            math.acos(((side2_length**2) + (side3_length**2) -
                       (side1_length**2)) / (2 * side2_length * side3_length)))

        if self.mx <= self.user.rect.x + (self.user.width / 2):
            self.deg_rotate *= -1
            self.pivot_side = -1
            self.rect.x = self.user.rect.x - (self.width / 2) + 10
            self.pivot = self.user.width
        if self.mx >= self.user.rect.x + (self.user.width / 2):
            self.pivot_side = 1
            self.rect.x = self.user.rect.x - (self.width /
                                              2) + (self.user.width) - 10
            self.pivot = self.user.width

        self.pivot_offset = pg.math.Vector2(
            0, self.pivot).rotate(-self.deg_rotate)

        self.rotated_image = pg.transform.rotate(self.image, self.deg_rotate)
        self.rotated_rect = self.rotated_image.get_rect(
            center=self.rect.center + self.pivot_offset)

        if (pg.time.get_ticks() - self.last_shot) > self.shot_interval:
            self.shoot()
            self.last_shot = pg.time.get_ticks()
    def updateMovement(self, step):
        angle = self.angle
        self.prevAngle = angle
        # print("prevAngle ", math.degrees(self.prevAngle))
        position = self.position
        self.prevPosition = position
        # print("PREV position = ", self.prevPosition)

        dx = self.position.x - planetCenter.x
        dy = self.position.y - planetCenter.y

        r = math.sqrt(dx ** 2 + dy ** 2)
        g = Physics.G * self.mass * planetMass / r ** 2

        self.radialVelocity += g
        if (self.radialVelocity < PLAYER_MIN_SPEED):
            self.radialVelocity = PLAYER_MIN_SPEED
        self.radius += self.radialVelocity

        # print("radius ", self.radius)

        bottom = self.radius - self.halfHeight
        self.onGround = False

        if (bottom <= planetRadius):
            self.onGround = True
            self.radius = planetRadius + self.halfHeight
            self.radialVelocity = 0

        if self.onGround == True and self.direction == 'none':
            self.angularVelocity = 0
        self.angle += self.angularVelocity * planetRadius / self.radius
        # print("angle ", self.angle)
        # print("angle ", math.degrees(self.angle))
        if (math.degrees(self.angle) >= 360.0):
            self.angle = 0.0

        # self.position.x = planetCenter.x + self.radius * math.sin(self.angle)
        # self.position.y = planetCenter.y + self.radius * -math.cos(self.angle)
        newPosition = Vector2()
        newPosition.x = planetCenter.x + self.radius * math.sin(self.angle)
        newPosition.y = planetCenter.y + self.radius * -math.cos(self.angle)

        positionChange = newPosition - position
        # print("positionChange = ", positionChange)

        self.position.x += positionChange.x * step
        self.position.y += positionChange.y * step
Exemple #5
0
    def update(self):
        # Delete the object if all health is lost
        if self.health <= 0:
            self.follow.enemies_killed += 1
            self.kill()
        #Pythag to find distance from player
        self.c = math.sqrt((self.follow.rect.x - self.rect.x)**2 +
                           (self.follow.rect.y - self.rect.y)**2)

        if self.c != 0:
            #Create a multiplier from the distance between the player
            self.x = (self.follow.rect.x - self.rect.x) / self.c
            self.y = (self.follow.rect.y - self.rect.y) / self.c

        #use multiplier to effect speed
        # self.rect.x += self.x * self.speed
        # self.rect.y += self.y * self.speed

        if self.x > 0:
            self.move_player(self.speed, 0)
            self.x_direction = 'r'
        if self.x < 0:
            self.move_player(-self.speed, 0)
            self.x_direction = 'l'

        if self.y < 0:
            self.move_player(0, -self.speed)
            self.y_direction = 'd'
        if self.y > 0:
            self.move_player(0, self.speed)
            self.y_direction = 'u'

        bullet_collisions = pg.sprite.spritecollide(self, self.bulletgroup,
                                                    True)
        #If there is bullet from the player colliding with the enemy, it will add it to the group, and if there is anything in this group, remove health
        if bullet_collisions:
            self.health -= self.follow.weapon.damage

        self.image.set_colorkey(BLACK)
Exemple #6
0
def lineIntersectsCircle(x1, y1, x2, y2, cx, cy, cr):
    r = cr
    Q = pygame.math.Vector2((cx, cy))
    P1 = pygame.math.Vector2((x1, y1))
    V = pygame.math.Vector2((x2, y2)) - P1
    
    a = V.dot(V)
    b = 2 * V.dot(P1 - Q)
    c = P1.dot(P1) + Q.dot(Q) - 2 * P1.dot(Q) - r**2
    
    disc = b**2 - 4 * a * c
    if disc < 0:
        return False
    
    sqrt_disc = math.sqrt(disc)
    t1 = (-b + sqrt_disc) / (2 * a)
    t2 = (-b - sqrt_disc) / (2 * a)
    
    if not (0 <= t1 <= 1 or 0 <= t2 <= 1):
        return False
    
    t = max(0, min(1, - b / (2 * a)))
    return True
Exemple #7
0
    def update(self, coordsOffset):
        vector: pygame.math.Vector2 = self.nodeAnchor.connectedNodes[
            self.nodeDestination][
                0]  # Define variables for vector from nodeAnchor to destination
        carVector: pygame.math.Vector2 = pygame.math.Vector2([
            b - a for a, b in zip(self.coords, self.nodeDestination.coords)
        ])  # variable vector from nodeAnchor to car

        try:
            normalized = vector.normalize()
        except ValueError:
            normalized = [0, 0]

        # Change the direction of the car if reached the end of the road
        change = False
        if normalized != carVector.normalize(
        ):  # if length to car from nodeAnchor is more than length to destination,
            # set the destinationNode as node anchor, and pick one random nodeDestination from the list of the new nodeAnchor
            self.nodeAnchor = self.nodeDestination
            numOfConnectedRoads = len(self.nodeAnchor.connectedNodes)

            # Issue object deletion
            if numOfConnectedRoads == 0:
                Car.carCollisionGrid[self.gridPos].pop(
                    Car.carCollisionGrid[self.gridPos].index(self))
                del self
                return True

            nodeDestinationIndex = random.randint(0, numOfConnectedRoads - 1)
            self.nodeDestination = list(
                self.nodeAnchor.connectedNodes.keys())[nodeDestinationIndex]
            # Change the coords
            change = True  # Then change the original from nodeAnchor to destination vector.

        if change:
            vector: pygame.math.Vector2 = self.nodeAnchor.connectedNodes[
                self.nodeDestination][0]
            self.direction = 360 - (np.arctan2(*vector[::-1]) * 180 / math.pi
                                    )  # Fix this
            self.image, self.rect = GMfun.rotationAnchor(
                self.originalImage, self.direction, [0.28, 0.5])

        #################################################### GridPos repositioning ####################################################
        currentGridPos = tuple([
            int(self.coords[i] // Car.collisionGridSize[i]) for i in range(2)
        ])
        if currentGridPos != self.gridPos:
            # Pop current car from the previous collisionGrid
            Car.carCollisionGrid[self.gridPos].pop(
                Car.carCollisionGrid[self.gridPos].index(self))

            # Add current car to new grid, and assign new gridPos to self
            self.gridPos = currentGridPos
            try:
                Car.carCollisionGrid[self.gridPos].append(self)
            except KeyError:
                Car.carCollisionGrid[self.gridPos] = [self]

        #################################################### Collision checking ####################################################
        self.carInFront = False  # Collision stuff. True if a car is detected in front.
        collisionCheckList = []
        for i in range(-1, 2):
            for j in range(-1, 2):
                try:
                    collisionCheckList += Car.carCollisionGrid[tuple(
                        [self.gridPos[0] + i, self.gridPos[1] + j])]
                except KeyError:
                    pass

        distanceFromNearestCar = 10000000000

        viewConeBase = [
            (Car.triangleHeight * normalized[i]) + self.coords[i] + 8
            for i in range(2)
        ]

        offsetVector1 = [-normalized[1], normalized[0]]
        viewConeBase1 = [
            a + (Car.triangleBase / 2 * c)
            for a, c in zip(viewConeBase, offsetVector1)
        ]
        offsetVector2 = [-vec for vec in offsetVector1]
        viewConeBase2 = [
            a + (Car.triangleBase / 2 * c)
            for a, c in zip(viewConeBase, offsetVector2)
        ]
        for cars in collisionCheckList:
            # Ignore if the car object is self, or if the nodeAnchor of self is not the same as other nodeAnchor
            if cars == self:
                continue

            carCoords = cars.coords
            # If the coords is within the cone
            if isPointInTriangle(carCoords, self.coords, viewConeBase1,
                                 viewConeBase2):
                distanceVector = pygame.math.Vector2(
                    *[b - a for a, b in zip(self.coords, carCoords)])
                if distanceVector.length_squared() < distanceFromNearestCar:
                    distanceFromNearestCar = distanceVector.length_squared()
                distanceFromNearestCar = math.sqrt(distanceFromNearestCar)
                self.carInFront = not cars.go if type(
                    cars
                ).__name__ == "StopLight" and cars.nodeAnchor == self.nodeAnchor else True

        ################################################## END COLLISION CHECKING ##################################################

        accelAddition = GMvar.deltaTime * self.acceleration * GMvar.gameSpeed
        if distanceFromNearestCar < Car.triangleHeight and self.carInFront:
            # self.scalarSpeed = self.oldScalarSpeed * ( GMfun.clamp(distanceFromNearestCar - Car.stopDistance, 0, Car.triangleHeight - Car.stopDistance) / (Car.triangleHeight - Car.stopDistance) )
            self.scalarSpeed -= self.brakeDeacceleration * GMvar.gameSpeed * GMvar.deltaTime * (
                1 - (GMfun.clamp(distanceFromNearestCar +
                                 Car.stopDistance, 0, Car.triangleHeight) /
                     Car.triangleHeight)) if self.scalarSpeed * 1 >= 0 else 0
        else:
            if not carVector.length_squared() < 112 ^ 2:
                self.scalarSpeed += accelAddition if self.scalarSpeed * 1 <= self.maxSpeed else 0
            else:
                self.scalarSpeed -= accelAddition * 2 if self.scalarSpeed > kmhToPixels(
                    20) else 0
            self.oldScalarSpeed = self.scalarSpeed

        self.scalarSpeed = GMfun.clamp(self.scalarSpeed, 0, 100000)
        self.speed = [
            self.scalarSpeed * vec * GMvar.gameSpeed for vec in normalized
        ]
        super().update()

        if change:
            self.coords = self.nodeAnchor.coords * 1

        self.surface.blit(self.image, [
            a - b + c for a, b, c in zip(self.coords, coordsOffset, self.rect)
        ])
        return False
Exemple #8
0
    def update():

        # Update mouse coords when snapped to grid
        Canvas.mouseCoords = [
            (GMvar.latestMouse[i] -
             ((GMvar.latestMouse[i] + MainCameraSurface.gridOffset[i]) %
              MainCameraSurface.cellSize[i])) for i in range(2)
        ]

        if Canvas.newRoad:
            Canvas.highlightGrid(1, 1)  # Grid highlight size
            GMfun.insertDrawTopMostQueue(Canvas.addRoad,
                                         (5, 25))  # Instructions

            if pygame.K_ESCAPE in GMvar.keyboardPressedStates:
                bottomGui.addRoad.clicked = False
                del Canvas.tempRoadNodes[:]

            length = 0  # Road length for now
            canDrawRoad = True  # If can draw road, not intersecting with others
            lengthFromIntersection = Canvas.snapLength + 1  # The length from the intersection point to the road to the mouse. (This is just the default valie)
            snap = False  # If the length fo intersection is lower than constant snap. it means the road is snapped to another road.
            overDirection = False
            # Draw road estimation
            if len(Canvas.tempRoadNodes) > 0:
                startLine = [
                    a - b for a, b in zip(Canvas.tempRoadNodes[-1].coords,
                                          MainCameraSurface.cameraCoords)
                ]
                endLine = Canvas.mouseCoords

                length = math.sqrt(
                    sum([(b - a)**2 for a, b in zip(startLine, endLine)
                         ])) * 0.1875  # Road length in meters

                # If intersects, disable road drawing
                combinedNode = [Canvas.roadNodes, Canvas.tempRoadNodes[:-2]]
                realMouseCoords = [
                    a + b
                    for a, b in zip(endLine, MainCameraSurface.cameraCoords)
                ]  # Real mouse coordinates. (mouse coords current - camera coords)
                # To avoid any unwanted intersections, offset node coords a bit.
                try:
                    newRoadVec = pygame.math.Vector2([
                        a - b for a, b in zip(realMouseCoords,
                                              Canvas.tempRoadNodes[-1].coords)
                    ]).normalize()
                except:
                    newRoadVec = [0, 0]

                intersectionCount = 0
                # Code for drawing temporary road to mouse.
                for i in range(2):
                    for j in range(len(combinedNode[i])):
                        for k in range(
                                len(combinedNode[i][j].connectedNodes.keys())):
                            # Check for intersections between 2 lines. one line is from the last temporary node to mouse coord. second line is every possible road.
                            state, pos = GMmat.checkLineIntersection(
                                [
                                    a + b for a, b in zip(
                                        newRoadVec,
                                        Canvas.tempRoadNodes[-1].coords)
                                ], realMouseCoords, combinedNode[i][j].coords,
                                list(combinedNode[i][j].connectedNodes.keys())
                                [k].coords, True)
                            # If current mouse coordinates connects to road then snap road.
                            # if realMouseCoords == combinedNode[i][j].coords:
                            #     state = True
                            #     pos = combinedNode[i][j].coords
                            # If intersecting then
                            if state:
                                intersectionCount += 1
                                # Calculate length from intersection.
                                lengthFromIntersection = math.sqrt(
                                    sum([(a - b)**2
                                         for a, b in zip(pos, realMouseCoords)
                                         ]))
                                snap = lengthFromIntersection < Canvas.snapLength
                                canDrawRoad = True if snap else False
                                # The node data for the one intersecting
                                # If snap then
                                if snap:
                                    # pos = [ pos[i] - (pos[i] % MainCameraSurface.cellSize[i]) for i in range(2) ] # If want to snap to grid, do this.
                                    firstNode: StreetNodes = combinedNode[i][j]
                                    secondNode: StreetNodes = list(
                                        combinedNode[i]
                                        [j].connectedNodes.keys())[k]
                                    break  # Break from for loop
                        if canDrawRoad == False or snap:
                            break  # Continue breaking
                    if canDrawRoad == False or snap: break  # Still breaking

                if intersectionCount > 1:
                    canDrawRoad = False

                # This is the script to check if road is going back 180 degrees, overlapping the previous road.
                # This works by comparing the normalized vector2 of the before road, and the current road by mouse.
                # Fixed problem where you can't place roads if there is two or more connectedNodes
                if len(Canvas.tempRoadNodes) > 1:
                    # vec1: pygame.math.Vector2 = list(Canvas.tempRoadNodes[-2].connectedNodes.values())[-1][0]
                    # vec2 = pygame.math.Vector2( [ b - a for a, b in zip(realMouseCoords, Canvas.tempRoadNodes[-1].coords) ] )
                    # try:
                    #     if vec1.normalize() == vec2.normalize():
                    #         canDrawRoad = False
                    #         snap = False
                    # except:
                    #     pass
                    # Redundant code

                    roadMouseDirection = (np.arctan2(*newRoadVec[::-1]) * 180 /
                                          math.pi)
                    roadMouseDirection = 360 + roadMouseDirection if roadMouseDirection < 0 else roadMouseDirection
                    addDir = Canvas.addRoadDirection + Canvas.directionRange / 2
                    minDir = Canvas.addRoadDirection - Canvas.directionRange / 2
                    if not ((roadMouseDirection < addDir or
                             (roadMouseDirection - 360 < addDir
                              and roadMouseDirection - 360 > minDir)) and
                            (roadMouseDirection > minDir or
                             (roadMouseDirection + 360 > minDir
                              and roadMouseDirection + 360 < addDir))):
                        canDrawRoad = False
                        overDirection = True
                        snap = False

                color = (52, 139, 201) if snap else ((50, 150,
                                                      50) if canDrawRoad else
                                                     (150, 50, 50))
                GMfun.drawBetterLine(
                    GMvar.mainScreenBuffer, color, *[
                        b + 16 if (b > a - c) else b for a, b, c in zip(
                            pos, startLine, MainCameraSurface.cameraCoords)
                    ] if snap else startLine, *[
                        a - b
                        for a, b in zip(pos, MainCameraSurface.cameraCoords)
                    ] if snap else endLine, 16
                )  # If snaps to road, change the end line to the snapped position, else to mouse position
                GMfun.insertDrawTopMostQueue(
                    GMvar.defFont12.render(
                        "Length: {}m".format(str(round(length, 3))), True,
                        (0, 0, 0)),
                    (GMvar.latestMouse[0] + 20,
                     GMvar.latestMouse[1]))  # Draw road estimation description
                GMfun.insertDrawTopMostQueue(
                    GMvar.defFont12.render(
                        "Total length: {}m".format(
                            str(round(Canvas.temporaryLength, 3))), True,
                        (0, 0, 0)),
                    (GMvar.latestMouse[0] + 20, GMvar.latestMouse[1] +
                     10))  # Draw road estimation description

            beginConnectRoad = False
            # If clicked on a road when temporary road is still empty.
            # This creates a new intersection point on the position where the mouse hovers, allowing the user to make a new road node from existing roads.
            if len(Canvas.tempRoadNodes) == 0:
                for i in range(len(Canvas.roadNodes)):
                    for connectedNodes in Canvas.roadNodes[
                            i].connectedNodes.keys():
                        point = Point(Canvas.mouseCoords)
                        line = LineString([
                            Canvas.roadNodes[i].coords, connectedNodes.coords
                        ])
                        if point.intersection(line):
                            pos = point
                            firstNode: StreetNodes = Canvas.roadNodes[i]
                            canDrawRoad = True
                            beginConnectRoad = True
                            break
                    if beginConnectRoad: break

            # Draw temporary roads when left clicked
            if GMvar.mouseStateSingle[0] and GMvar.latestMouse[
                    1] < bottomGui.guiHeightChange + bottomGui.sliderHeight and canDrawRoad and not overDirection:
                # Add length to total length
                Canvas.temporaryLength += length
                # If mouse is clicked on the canvas,
                if not snap:
                    newMouseCoords = [
                        MainCameraSurface.getRealMouseCoords()[i] -
                        ((MainCameraSurface.getRealMouseCoords()[i] %
                          MainCameraSurface.cellSize[i])) for i in range(2)
                    ]  # New mouse coords adjusted with the camera
                    newNode = StreetNodes(
                        newMouseCoords, [],
                        [firstNode] if beginConnectRoad else
                        ([Canvas.tempRoadNodes[-1]]
                         if len(Canvas.tempRoadNodes) > 0 else []), 0
                    )  # Create new object StreetNodes with current snapped mouse coordinates, empty front nodes, with back nodes from the last added.
                    if beginConnectRoad:
                        firstNode.connectTo(newNode)
                else:
                    ###################### Creates entirely new node, deletes already preexisting node.
                    # newNode = StreetNodes( pos, [secondNode], [Canvas.tempRoadNodes[-1]] if len(Canvas.tempRoadNodes) > 0 else [], 0 )
                    # for i in range(len(secondNode.backNodes)):
                    #     if secondNode.backNodes[i] == firstNode:
                    #         secondNode.backNodes[i] = newNode
                    # del firstNode.connectedNodes[secondNode]
                    # firstNode.connectedNodes[newNode] = pygame.math.Vector2( [ a - b for a, b in zip(firstNode.coords, pos) ] )
                    ###################### Creates new node, but overlaps with other node.
                    newNode = StreetNodes(
                        pos, [secondNode], [Canvas.tempRoadNodes[-1]]
                        if len(Canvas.tempRoadNodes) > 0 else [], 0
                    )  # Draw new node, with the connected node to the second node.
                    firstNode.connectTo(newNode)
                if len(Canvas.tempRoadNodes) > 0:
                    Canvas.addRoadDirection = (np.arctan2(*[
                        b - a
                        for a, b in zip(Canvas.tempRoadNodes[-1].coords[::-1],
                                        newNode.coords[::-1])
                    ]) * 180 / math.pi)
                    Canvas.addRoadDirection = 360 + Canvas.addRoadDirection if Canvas.addRoadDirection < 0 else Canvas.addRoadDirection
                    Canvas.tempRoadNodes[-1].connectTo(
                        newNode
                    )  # Add newNode to front node of the previous StreetNode
                Canvas.tempRoadNodes.append(
                    newNode)  # Add newNode to current roadNodes list

            # When Enter clicked, save current temp roads to road nodes
            if pygame.K_RETURN in GMvar.keyboardPressedStates:
                Canvas.roadNodes += Canvas.tempRoadNodes
                del Canvas.tempRoadNodes[:]
        else:
            Canvas.temporaryLength = 0
            Canvas.addRoadDirection = 0

        if Canvas.editRoad:
            Canvas.highlightGrid(1, 1)  # Grid highlight size
            GMfun.insertDrawTopMostQueue(Canvas.editRoadText,
                                         (5, 25))  # Instructions

            # When mouse is held, draw selection rectangle
            if GMvar.mouseState[0]:
                del Canvas.tempRoadNodes[:]
                rectSize = [
                    a - b
                    for a, b in zip(GMvar.latestMouse, GMvar.latestMouseLeft)
                ]
                rectSurface = pygame.Surface([abs(num) for num in rectSize])
                rectSurface.set_alpha(100)
                rectSurface.fill((84, 184, 214))
                rectCoords = GMvar.latestMouseLeft
                rectCoords = [
                    a + b if b < 0 else a
                    for a, b in zip(rectCoords, rectSize)
                ]
                GMvar.mainScreenBuffer.blit(rectSurface, rectCoords)

                rectCoords = [
                    a + b
                    for a, b in zip(rectCoords, MainCameraSurface.cameraCoords)
                ]

                Canvas.selectionRect = [
                    *rectCoords, *[
                        a + b
                        for a, b in zip([abs(num)
                                         for num in rectSize], rectCoords)
                    ]
                ]

            # When mouse is released, all the roads intersecting and the nodes inside of the selection is copied into a list
            if not GMvar.mouseState[0] and len(Canvas.selectionRect) > 0:
                # Make a rectangle shapely object from the selection made
                rectangleGeometry = box(*Canvas.selectionRect)
                # Check if nodes / line intersection is in selection
                for nodes in Canvas.roadNodes:
                    for connectedNodes in nodes.connectedNodes.keys():
                        line = LineString(
                            [nodes.coords, connectedNodes.coords])
                        # If line is intersecting with selection rect, then append to list
                        if line.intersects(rectangleGeometry):
                            Canvas.tempRoadNodes.append(nodes)
                            break
                    # If node is in selection rect, then append to list
                    if nodes.coords[0] > Canvas.selectionRect[
                            0] and nodes.coords[0] < Canvas.selectionRect[2]:
                        if nodes.coords[1] > Canvas.selectionRect[
                                1] and nodes.coords[1] < Canvas.selectionRect[
                                    3]:
                            Canvas.tempRoadNodes.append(nodes)

            # Delete selection rect if mouse is not clicked
            if not GMvar.mouseState[0]:
                del Canvas.selectionRect[:]

            # Recreate new canvas.roadnodes without anything in canvas temproadnodes. so, basically Canvas.roadNodes = Canvas.roadNodes - Canvas.tempRoadNodes
            if pygame.K_DELETE in GMvar.keyboardPressedStates or pygame.K_BACKSPACE in GMvar.keyboardPressedStates and len(
                    Canvas.tempRoadNodes) > 0:
                # If an element of roadnodes is in temproadnodes, delete the connectedRoads element of the roadnodes' backnode.
                # for i in range(len(Canvas.roadNodes)):
                #     if Canvas.roadNodes[i] in Canvas.tempRoadNodes:
                #         for j in range(len(Canvas.roadNodes[i].backNodes)):
                #             del Canvas.roadNodes[i].backNodes[j].connectedNodes[Canvas.roadNodes[i]] # NEED SOME FIXING HOMIE
                # Delete from roadnodes
                Canvas.roadNodes = [
                    nodes for nodes in Canvas.roadNodes
                    if nodes not in Canvas.tempRoadNodes
                ]
                # Delete any reference to deleted roads, to avoid car crossing the road even after deleted.
                # Dont forget to delete cars too.
                for deletedNodes in Canvas.tempRoadNodes:
                    deletedNodes.connectedNodes = {}
                    deletedCars = 0
                    for i in range(len(Canvas.cars)):
                        i -= deletedCars
                        if Canvas.cars[i].nodeAnchor == deletedNodes:
                            # Delete from collision grid
                            gridPos = tuple([
                                Canvas.cars[i].coords[j] //
                                Car.collisionGridSize[j] for j in range(2)
                            ])
                            del Car.carCollisionGrid[gridPos][
                                Car.carCollisionGrid[gridPos].index(
                                    Canvas.cars[i])]
                            # Finally, delete form Canvas' list
                            Canvas.cars.pop(i)
                            deletedCars += 1  # add 1 to i
                    deletedSpawners = 0
                    for i in range(len(Canvas.carSpawners)):
                        i -= deletedSpawners
                        if Canvas.carSpawners[i].nodeAnchor == deletedNodes:
                            Canvas.carSpawners.pop(i)
                            deletedSpawners += 1
                    deletedStopLights = 0
                    for i in range(len(Canvas.stopLights)):
                        i -= deletedStopLights
                        if Canvas.stopLights[i].nodeAnchor == deletedNodes:

                            gridPos = tuple([
                                Canvas.stopLights[i].coords[j] //
                                Car.collisionGridSize[j] for j in range(2)
                            ])
                            del Car.carCollisionGrid[gridPos][
                                Car.carCollisionGrid[gridPos].index(
                                    Canvas.stopLights[i])]

                            Canvas.stopLights.pop(i)
                            deletedStopLights += 1

                del Canvas.tempRoadNodes[:]
        else:
            del Canvas.selectionRect[:]

        if Canvas.addCarSpawner:
            if GMvar.mouseStateSingle[0]:
                selected = selectRoad(MainCameraSurface.getRealMouseCoords(),
                                      Canvas.roadNodes, 16)
                if selected != None:
                    node, connectedNode, selectedCoord = selected
                    Canvas.carSpawners.append(
                        CarSpawner(node, selectedCoord, kmhToPixels(40), 30))

        if Canvas.addCar:
            if GMvar.mouseStateSingle[0]:
                try:
                    selected = selectRoad(
                        MainCameraSurface.getRealMouseCoords(),
                        Canvas.roadNodes, 16)
                except:
                    selected = None

                if selected != None:
                    node, connectedNode, selectedCoord = selected

                    anotherCarIsNear = False
                    carChecklist = []
                    gridPos = tuple([
                        int(selectedCoord[i] // Car.collisionGridSize[i])
                        for i in range(2)
                    ])
                    for i in range(-1, 2):
                        for j in range(-1, 2):
                            try:
                                carChecklist += Car.carCollisionGrid[tuple(
                                    [gridPos[0] + i, gridPos[1] + j])]
                            except KeyError:
                                pass

                    for cars in carChecklist:
                        pointToCarVector = pygame.math.Vector2([
                            a - b for a, b in zip(selectedCoord, cars.coords)
                        ])
                        if pointToCarVector.length_squared() < 40**2:
                            anotherCarIsNear = True
                    del carChecklist

                    if not anotherCarIsNear:
                        # Search for the absolute end of the road (curEndNode)
                        longestLength = 0
                        curEndNode: StreetNodes = None
                        for connected in node.connectedNodes:
                            curLength = node.connectedNodes[connected][
                                0].length_squared()
                            if curLength > longestLength:
                                curEndNode = connected
                                longestLength = curLength

                        # Define start point and end point
                        lineToCheck = LineString([[*selectedCoord],
                                                  [*curEndNode.coords]])

                        roadSplitChoices = []

                        for connected in node.connectedNodes:
                            if Point(connected.coords).intersects(lineToCheck):
                                roadSplitChoices.append(connected)

                        Canvas.cars.append(
                            Car(
                                node, roadSplitChoices[random.randint(
                                    0,
                                    len(roadSplitChoices) - 1)],
                                kmhToPixels(40), selectedCoord,
                                GMvar.mainScreenBuffer))
                        del roadSplitChoices  # Delete references

        if Canvas.addStopLight:

            if GMvar.mouseStateSingle[0]:
                selected = selectRoad(MainCameraSurface.getRealMouseCoords(),
                                      Canvas.roadNodes, 16)
                if selected != None:
                    node, connectedNode, selectedCoord = selected

                    gridPos = tuple([
                        int(selectedCoord[i] // Car.collisionGridSize[i])
                        for i in range(2)
                    ])
                    stopLight = StopLight(node, GMvar.mainScreenBuffer,
                                          selectedCoord, 5, 10)
                    try:
                        Car.carCollisionGrid[gridPos].append(stopLight)
                    except KeyError:
                        Car.carCollisionGrid[gridPos] = [stopLight]

                    Canvas.stopLights.append(stopLight)

        if Canvas.resetStopLight:
            for stopLights in Canvas.stopLights:
                stopLights.go = True
                stopLights.timer = GMfun.Timer(stopLights.greenDuration * 1000)

        Canvas.drawRoads(Canvas.roadNodes, (30, 30, 30))
        Canvas.drawRoads(Canvas.tempRoadNodes,
                         (50, 150, 50) if Canvas.newRoad else (52, 192, 217))

        # Update and draw CarSpawners
        for spawners in Canvas.carSpawners:
            spawners.update(Canvas.cars, GMvar.mainScreenBuffer,
                            MainCameraSurface.cameraCoords)

        # Update and draw cars
        deletedCars = 0
        for i in range(len(Canvas.cars)):
            # If car has reached its end-destination then
            i -= deletedCars
            if Canvas.cars[i].update(MainCameraSurface.cameraCoords):
                # Delete car from list. Then, index is subtracted by 1, so not outOfRangeError
                Canvas.cars.pop(i)
                deletedCars += 1

        # Update stoplights
        for stopLights in Canvas.stopLights:
            stopLights.update(MainCameraSurface.cameraCoords)