parent
							
								
									ae14326fe8
								
							
						
					
					
						commit
						4c59532a9f
					
				
				 6 changed files with 583 additions and 0 deletions
			
			
		| After Width: | Height: | Size: 2.3 KiB | 
| @ -0,0 +1,341 @@ | ||||
| import time, datetime, math | ||||
| from copy import deepcopy | ||||
| from enum import Enum | ||||
| 
 | ||||
| def now(): | ||||
|     return datetime.datetime.now().timestamp() | ||||
| 
 | ||||
| class DroneState(Enum): | ||||
|     Grounded = 0 | ||||
|     InTheAir = 1 | ||||
|     WaitingForTakeOff = 2 | ||||
| 
 | ||||
| class StopType(Enum): | ||||
|     City = 0 | ||||
|     Factory = 1 | ||||
| 
 | ||||
| class Position: | ||||
|     def __init__(self, x, y): | ||||
|         self.x = x | ||||
|         self.y = y | ||||
|     def __str__(self): | ||||
|         return(f"[{self.x}, {self.y}]")  | ||||
| 
 | ||||
| class Drone: | ||||
|     def __init__(self, name, position, route, rate, capacity): | ||||
|         self.__name = name | ||||
|         self.__position = position | ||||
|         self.__route = route | ||||
|         self.__rate = rate # per second | ||||
|         self.__capacity = capacity | ||||
|         self.__cargo = {} | ||||
| 
 | ||||
|         self.__state = DroneState.Grounded | ||||
|         self.__prevousStop = -1 | ||||
|         self.__nextStop = 0 | ||||
|         self.__lastDeparture = 0 | ||||
|         self.__lastDeparturePosition = deepcopy(position) | ||||
| 
 | ||||
|     def set_position(self, position): | ||||
|         self.__position = position | ||||
| 
 | ||||
|     # returns how much was accepted from the load | ||||
|     def load_cargo(self, product, quantity): | ||||
|         cargoTotal = self.get_cargo_total() | ||||
| 
 | ||||
|         if not product in self.__cargo: | ||||
|             self.__cargo[product] = 0 | ||||
| 
 | ||||
|         spaceRemaining = (self.__capacity - cargoTotal) | ||||
| 
 | ||||
|         acceptedQuantity = quantity | ||||
| 
 | ||||
|         # if the quantity is more than space remaining then just return the space remaining | ||||
|         if(quantity > spaceRemaining): | ||||
|             acceptedQuantity = spaceRemaining | ||||
| 
 | ||||
|         self.__cargo[product] += acceptedQuantity | ||||
| 
 | ||||
|         return acceptedQuantity | ||||
|   | ||||
|     def get_cargo_total(self): | ||||
|         total = 0 | ||||
|          | ||||
|         for key in self.__cargo: | ||||
|             total += self.__cargo[key] | ||||
|          | ||||
|         return total | ||||
| 
 | ||||
|     def takeOff(self): | ||||
|         self.__state = DroneState.InTheAir | ||||
|         self.__lastDeparture = now() | ||||
|         self.__lastDeparturePosition = deepcopy(self.__position) | ||||
| 
 | ||||
|         positionFound = False | ||||
| 
 | ||||
|         for idx, stop in enumerate(self.__route.get_stops()): | ||||
|             stopPosition = stop.get_position() | ||||
|              | ||||
|             if (stopPosition.x == self.__position.x) and (stopPosition.y == self.__position.y): | ||||
|                 positionFound = True | ||||
| 
 | ||||
|                 self.__prevousStop = idx | ||||
|                  | ||||
|                 # if the next stop is out of range, loop back home | ||||
|                 if(idx + 1 == len(self.__route.get_stops())): | ||||
|                     self.__nextStop = 0 | ||||
|                 else: | ||||
|                     self.__nextStop = idx + 1 | ||||
|          | ||||
|         if(not positionFound): | ||||
|             self.__prevousStop = -1 | ||||
|             self.__nextStop = 0 | ||||
|             print(f"{self.__name}: Taking off from: {self.__position}") | ||||
|         else: | ||||
|             print(f"{self.__name}: Taking off from: {self.__route.get_stops()[self.__prevousStop]}") | ||||
| 
 | ||||
|     def cargo_report(self): | ||||
|         str = "" | ||||
|         for product in self.__cargo: | ||||
|             str += f"{product}: {self.__cargo[product]}" | ||||
|         return | ||||
| 
 | ||||
|     def update(self): | ||||
| 
 | ||||
|         state = DroneState.Grounded.name | ||||
|         position = f"Position: {self.__position}" | ||||
|         prevousStop = self.__route.get_stops()[self.__prevousStop] | ||||
|         nextStop = self.__route.get_stops()[self.__nextStop] | ||||
| 
 | ||||
|         # print cargo levels | ||||
|         print(f"{self.__name}: On Board {self.__cargo}") | ||||
| 
 | ||||
|         # are we at a unknown location? | ||||
|         if(self.__prevousStop == -1): | ||||
|             location = self.__lastDeparturePosition | ||||
|         else: | ||||
|             location = prevousStop | ||||
| 
 | ||||
|         # is the drone in the air? | ||||
|         if(self.__state == DroneState.Grounded): | ||||
|             print(f"{self.__name}: {state}: {location}") | ||||
|         elif(self.__state == DroneState.WaitingForTakeOff): | ||||
|             currentStop = prevousStop | ||||
| 
 | ||||
|             print(f"{self.__name}: Waiting For Take Off: {location}") | ||||
| 
 | ||||
|             # load cargo/receive_supplies if at a factory | ||||
|             if(currentStop.get_stop_type() == StopType.Factory): | ||||
|                 print(f"{self.__name}: Loading Inventory") | ||||
| 
 | ||||
|                 products = currentStop.get_output_quantity() | ||||
| 
 | ||||
|                 for key in products: | ||||
|                     acceptedQuantity = self.load_cargo(key, products[key]) | ||||
| 
 | ||||
|                     # adjust inventory by accepted quantity | ||||
|                     currentStop.update_inventory(-acceptedQuantity) | ||||
| 
 | ||||
|                 currentStop.receive_supplies(self.__cargo) | ||||
| 
 | ||||
|             if(self.__nextTakeOff <= now()): | ||||
|                 self.takeOff() | ||||
|         else: | ||||
|             print(f"{self.__name}: Traveling Between: {location} and {nextStop}") | ||||
| 
 | ||||
|             # time in the air since take off | ||||
|             timeDifference = math.floor(now() - self.__lastDeparture) | ||||
|              | ||||
|             x2 = float(nextStop.get_position().x) | ||||
|             y2 = float(nextStop.get_position().y) | ||||
| 
 | ||||
|             if(self.__prevousStop == -1): | ||||
|                 x1 = float(self.__lastDeparturePosition.x) | ||||
|                 y1 = float(self.__lastDeparturePosition.y) | ||||
|             else: | ||||
|                 x1 = prevousStop.get_position().x | ||||
|                 y1 = prevousStop.get_position().y | ||||
| 
 | ||||
|             #print(f"{self.__name}: {x1},{y1} -> {x2},{y2}") | ||||
| 
 | ||||
|             # total distance: d=√((x2 – x1)² + (y2 – y1)²) | ||||
|             totalDistance = (math.sqrt(abs(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))))) | ||||
| 
 | ||||
|             # d = rt | ||||
|             distanceTraveled = self.__rate * (now() - self.__lastDeparture) | ||||
| 
 | ||||
|             #print(f"{self.__name}: Distance Traveled: {distanceTraveled}, Total Distance: {totalDistance}") | ||||
| 
 | ||||
|             # slope m = (y2 - y1) / (x2 - x1) | ||||
|             if(x2 == x1): | ||||
|                 m = 0 | ||||
|             else: | ||||
|                 m = (y2 - y1) / (x2 - x1) | ||||
| 
 | ||||
|             travelingEast = x2 > x1 | ||||
|             travelingNorth = y2 > y1 | ||||
| 
 | ||||
|             # if traveled the distance, ground the drone and update stops | ||||
|             if(distanceTraveled >= totalDistance): | ||||
|                 # force position | ||||
|                 self.__position.x = nextStop.get_position().x | ||||
|                 self.__position.y = nextStop.get_position().y | ||||
| 
 | ||||
|                 self.__state = DroneState.WaitingForTakeOff | ||||
|                 self.__nextTakeOff = now() + 5 | ||||
|                 self.__prevousStop = self.__nextStop | ||||
|                 self.__nextStop += 1 | ||||
| 
 | ||||
|                 # if next stop out of range, sent back to first stop | ||||
|                 if(self.__nextStop >= len(self.__route.get_stops())): | ||||
|                     self.__nextStop = 0 | ||||
|             else: | ||||
|                 # what percentage of the journey has passed? | ||||
|                 per = (distanceTraveled/totalDistance) | ||||
| 
 | ||||
|                 # compute X | ||||
|                 if(travelingEast): | ||||
|                     x = x1 + ((x2 - x1) * per) | ||||
|                 else: | ||||
|                     x = x1 - ((x1 - x2) * per) | ||||
| 
 | ||||
|                 # compute y | ||||
|                 if(m > 0): | ||||
|                     # if there is a slope | ||||
|                     #(y – y1) = m(x – x1)  | ||||
|                     y = (m * (x - x1)) + y1 | ||||
|                 else: | ||||
|                     if(travelingNorth): | ||||
|                         y = y1 + ((y2 - y1) * per) | ||||
|                     else: | ||||
|                         y = y1 - ((y1 - y2) * per) | ||||
| 
 | ||||
|                     # if no slope, either x or y is constant | ||||
|                     if(x1 == x2): | ||||
|                         x = x1 | ||||
| 
 | ||||
|                     if(y1 == y2): | ||||
|                         y = y1 | ||||
| 
 | ||||
|                 self.__position.x = x | ||||
|                 self.__position.y = y | ||||
| 
 | ||||
|                 print(f"{self.__name} {position}") | ||||
|     def get_state(self): | ||||
|         return self.__state | ||||
| 
 | ||||
| class Route: | ||||
|     def __init__(self, name, stops): | ||||
|         self.__name = name | ||||
|         self.__stops = stops | ||||
|     def get_stops(self): | ||||
|         return self.__stops | ||||
|      | ||||
| class Product(): | ||||
|     def __init__(self, name): | ||||
|         self.__name = name | ||||
|     def __str__(self): | ||||
|         return f"{self.__name}" | ||||
|     def get_name(self): | ||||
|         return self.__name | ||||
| 
 | ||||
| class Stop: | ||||
|     def __init__(self, stopType, name, position): | ||||
|         self.__stopType = stopType | ||||
|         self.__name = name | ||||
|         self.__position = position | ||||
|     def __str__(self): | ||||
|         return f"{self.__name} {self.__position}" | ||||
|     def get_position(self): | ||||
|         return self.__position | ||||
|     def get_name(self): | ||||
|         return self.__name | ||||
|     def get_stop_type(self): | ||||
|         return self.__stopType | ||||
| 
 | ||||
| class Factory(Stop): | ||||
|     def __init__(self, name, position, product, buildRate, acceptedSupplies): | ||||
|         super().__init__(StopType.Factory, name, position) | ||||
| 
 | ||||
|         #product name | ||||
|         self.__product = product | ||||
|         #build rate (units per second) | ||||
|         self.__buildRate = buildRate | ||||
|         #units ready to ship | ||||
|         self.__inventory = {product: 0} | ||||
|         #last time inventory was updated | ||||
|         self.__lastCheck = 0 | ||||
|         #acceptedSupplies = products accepted by this factory | ||||
|         self.__acceptedSupplies = acceptedSupplies | ||||
|      | ||||
|     # returns a dictionary of the product and inventory level | ||||
|     def get_output_quantity(self): | ||||
|         # only return finished goods | ||||
|         return {self.__product: math.floor(self.__inventory[self.__product])} | ||||
|      | ||||
|     # adds to inventory level | ||||
|     def update_inventory(self, quantity): | ||||
|         self.__inventory[self.__product] += quantity | ||||
| 
 | ||||
|     def update_supply_inventory(self, product, quantity): | ||||
|         if product not in self.__inventory: | ||||
|             self.__inventory[product] = 0 | ||||
|              | ||||
|         self.__inventory[product] += quantity | ||||
| 
 | ||||
|     def receive_supplies(self, supplies): | ||||
|         for supply in supplies: | ||||
|             if supply in self.__acceptedSupplies: | ||||
|                 self.update_supply_inventory(supply, supplies[supply]) | ||||
| 
 | ||||
|     def inventory_report(self): | ||||
|         str = f"{self.get_name()}: " | ||||
|         for product in self.__inventory: | ||||
|             str += f"{product}: {self.__inventory[product]} " | ||||
|         return str | ||||
| 
 | ||||
|     # runs on timer tick | ||||
|     def update(self): | ||||
|         now = datetime.datetime.now().timestamp() | ||||
| 
 | ||||
|         if(self.__lastCheck > 0): | ||||
|             timeDifference = (now - self.__lastCheck) | ||||
|             self.update_inventory(timeDifference * self.__buildRate) | ||||
|              | ||||
|         print(self.inventory_report()) | ||||
| 
 | ||||
|         self.__lastCheck = datetime.datetime.now().timestamp() | ||||
| 
 | ||||
| chicago = Stop(StopType.City, "Chicago", Position(1, 45)) | ||||
| miami = Stop(StopType.City, "Miami", Position(50, 1)) | ||||
| newYork = Stop(StopType.City, "New York", Position(50, 50)) | ||||
| 
 | ||||
| widget = Product("Widget") | ||||
| gizmo = Product("Gizmo") | ||||
| 
 | ||||
| widgetFactory = Factory("Widget Inc", Position(50, 25), widget, .25, []) | ||||
| 
 | ||||
| gizmoSupplies = [widget] | ||||
| gizmoFactory = Factory("Gizmo Inc", Position(50, 30), gizmo, .25, gizmoSupplies) | ||||
| 
 | ||||
| factories = [widgetFactory, gizmoFactory] | ||||
| 
 | ||||
| route = Route(name="Express Route", stops=(widgetFactory, gizmoFactory)) | ||||
| routeRev = Route(name="Express Route Reverse", stops=(miami, newYork, chicago, widgetFactory))  | ||||
| 
 | ||||
| alphaDrone = Drone("Alpha", Position(25, 25), route, 1, 10) | ||||
| betaDrone = Drone("Beta", Position(35, 25), routeRev, 5, 10) | ||||
| 
 | ||||
| drones = [alphaDrone] | ||||
| 
 | ||||
| while(True): | ||||
|     for drone in drones: | ||||
|         if(drone.get_state() == DroneState.Grounded): | ||||
|             drone.takeOff() | ||||
|         else: | ||||
|             drone.update() | ||||
|     for factory in factories: | ||||
|         factory.update() | ||||
|         pass | ||||
| 
 | ||||
|     time.sleep(1) | ||||
| @ -0,0 +1,30 @@ | ||||
| import pygame | ||||
| 
 | ||||
| from settings import Settings | ||||
| from spritesheet import SquareSpriteSheet | ||||
| from ship import Drone | ||||
| 
 | ||||
| settings = Settings() | ||||
| 
 | ||||
| screen = pygame.display.set_mode((settings.width, settings.height)) | ||||
| pygame.display.set_caption(settings.caption) | ||||
| 
 | ||||
| pygame.init() | ||||
| 
 | ||||
| ship = Drone(screen, (0, 0)) | ||||
| 
 | ||||
| run = True | ||||
| 
 | ||||
| while run: | ||||
|     #update background | ||||
|     screen.fill(settings.background_color) | ||||
| 
 | ||||
|     ship.update() | ||||
| 
 | ||||
|     #event handler | ||||
|     for event in pygame.event.get(): | ||||
|         if event.type == pygame.QUIT: | ||||
|             run = False | ||||
|      | ||||
|     pygame.display.update() | ||||
| 
 | ||||
| @ -0,0 +1,6 @@ | ||||
| class Settings(): | ||||
|     def __init__(self) -> None: | ||||
|         self.width = 500 | ||||
|         self.height = 500 | ||||
|         self.caption = "My Game" | ||||
|         self.background_color = (50, 50, 50) | ||||
| @ -0,0 +1,172 @@ | ||||
| import pygame | ||||
| from enum import Enum | ||||
| import math | ||||
| import random | ||||
| 
 | ||||
| from spritesheet import SquareSpriteSheet | ||||
| 
 | ||||
| class DroneStatus(Enum): | ||||
|     GROUNDED = 0 | ||||
|     TAKINGOFF = 1 | ||||
|     TURNING = 2 | ||||
|     INTHEAIR = 3 | ||||
|     LANDING = 4 | ||||
| 
 | ||||
| class Drone: | ||||
|     def __init__(self, screen, pos = (0, 0)) -> None: | ||||
|          | ||||
|         # image | ||||
|         self.screen = screen | ||||
|         self.sheet = sheet = SquareSpriteSheet('assets/ship-sheet.png', 96, 4) | ||||
|         self.scale = 1 | ||||
|         self.angle = 0 | ||||
|          | ||||
|         # animation | ||||
|         self.frame = 0 | ||||
|         self.animation_cooldown = 75 | ||||
|          | ||||
|         # tracking | ||||
|         self.scale = .25 | ||||
|         self.last_update = 0 | ||||
|         self.pos = pos | ||||
|         self.prev_index = 0 | ||||
|         self.next_index = 1 | ||||
| 
 | ||||
|         self.route = [(400,400),(0,400),(400,0),(0,0),(400,0)] | ||||
|          | ||||
|         # status | ||||
|         self.status = DroneStatus.TAKINGOFF | ||||
|         self.animate = False | ||||
|         self.last_departure = 0 | ||||
| 
 | ||||
|         self.rate = 100/1000 #(units per second) | ||||
| 
 | ||||
|     def update(self): | ||||
| 
 | ||||
|         current_time = pygame.time.get_ticks() | ||||
| 
 | ||||
|         if(self.status == DroneStatus.GROUNDED): | ||||
|             self.prev_index = 0 | ||||
|             self.next_index = 1 | ||||
| 
 | ||||
|             self.scale = .25 | ||||
|             self.animate = False | ||||
| 
 | ||||
|         elif(self.status == DroneStatus.TAKINGOFF): | ||||
|             self.scale += .001 | ||||
| 
 | ||||
|             if(self.scale >= 1): | ||||
|                 self.scale = 1 | ||||
|                 self.status = DroneStatus.TURNING | ||||
| 
 | ||||
|             self.animate = True | ||||
|         elif(self.status == DroneStatus.TURNING): | ||||
|             x1 = self.route[self.prev_index][0] | ||||
|             y1 = self.route[self.prev_index][1] | ||||
| 
 | ||||
|             x2 = self.route[self.next_index][0] | ||||
|             y2 = self.route[self.next_index][1] | ||||
| 
 | ||||
|             #https://replit.com/@Rabbid76/PyGame-RotateWithMouse#main.py | ||||
| 
 | ||||
|             correction_angle = 90 | ||||
|             dx = x2 - x1 | ||||
|             dy = y2 - y1 | ||||
|             new_angle = math.degrees(math.atan2(-dy, dx)) - correction_angle | ||||
| 
 | ||||
|             if(int(self.angle) > int(new_angle)): | ||||
|                 self.angle -= .1 | ||||
|             elif(int(self.angle) < int(new_angle)): | ||||
|                 self.angle += .1 | ||||
| 
 | ||||
|             if((int(self.angle) + int(new_angle)) == 0): | ||||
|                 self.angle = new_angle | ||||
|                 self.last_departure = current_time | ||||
|                 self.status = DroneStatus.INTHEAIR | ||||
| 
 | ||||
|             if((int(self.angle) - int(new_angle)) == 0): | ||||
|                 self.angle = new_angle | ||||
|                 self.last_departure = current_time | ||||
|                 self.status = DroneStatus.INTHEAIR | ||||
|              | ||||
|             self.animate = True | ||||
| 
 | ||||
|         elif(self.status == DroneStatus.INTHEAIR): | ||||
|              | ||||
|             x1 = self.route[self.prev_index][0] | ||||
|             y1 = self.route[self.prev_index][1] | ||||
| 
 | ||||
|             x2 = self.route[self.next_index][0] | ||||
|             y2 = self.route[self.next_index][1] | ||||
| 
 | ||||
|             going_north = y2 >= y1 | ||||
|             going_east = x2 >= x1 | ||||
| 
 | ||||
|             slope = 0 | ||||
| 
 | ||||
|             if(x2 - x1 != 0): | ||||
|                 slope = (y2 - y1) / (x2 - x1) | ||||
| 
 | ||||
|             # total distance: d=√((x2 – x1)² + (y2 – y1)²) | ||||
|             total_distance = (math.sqrt(abs(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))))) | ||||
| 
 | ||||
|             # d = rt | ||||
|             distance_traveled = self.rate * (current_time - self.last_departure) | ||||
| 
 | ||||
|             # if traveled the distance, ground the drone and update stops | ||||
|             if(distance_traveled >= total_distance): | ||||
|             # force position | ||||
|                 self.pos = self.route[self.next_index] | ||||
| 
 | ||||
|                 self.status = DroneStatus.LANDING | ||||
|             else: | ||||
|                 # what percentage of the journey has passed? | ||||
|                 per = (distance_traveled/total_distance) | ||||
| 
 | ||||
|                 # compute X | ||||
|                 if(going_east): | ||||
|                     x = x1 + ((x2 - x1) * per) | ||||
|                 else: | ||||
|                     x = x1 - ((x1 - x2) * per) | ||||
| 
 | ||||
|                 # compute y | ||||
|                 if(slope > 0): | ||||
|                     # if there is a slope | ||||
|                     #(y – y1) = m(x – x1)  | ||||
|                     y = (slope * (x - x1)) + y1 | ||||
|                 else: | ||||
|                     if(going_north): | ||||
|                         y = y1 + ((y2 - y1) * per) | ||||
|                     else: | ||||
|                         y = y1 - ((y1 - y2) * per) | ||||
| 
 | ||||
|                     # if no slope, either x or y is constant | ||||
|                     if(x1 == x2): | ||||
|                         x = x1 | ||||
| 
 | ||||
|                     if(y1 == y2): | ||||
|                         y = y1 | ||||
| 
 | ||||
|                 self.pos = (x, y) | ||||
|             self.scale = 1 | ||||
|             self.animate = True | ||||
| 
 | ||||
|         elif(self.status == DroneStatus.LANDING): | ||||
|             self.scale -= .001 | ||||
| 
 | ||||
|             if(self.scale <= .25): | ||||
|                 self.scale = .25 | ||||
|                 self.status = DroneStatus.TAKINGOFF | ||||
|                 self.prev_index = self.next_index | ||||
|                 self.next_index = self.prev_index + 1 if self.prev_index + 1 < len(self.route) else 0 | ||||
| 
 | ||||
|             self.animate = True | ||||
| 
 | ||||
|         if(self.animate): | ||||
|             if current_time - self.last_update >= self.animation_cooldown: | ||||
|                 self.frame += 1 | ||||
|                 self.frame = self.frame if self.frame < len(self.sheet.images) else 0 | ||||
|                 self.last_update = current_time | ||||
| 
 | ||||
|         current_image = self.sheet.get_image_by_frame(self.frame, self.scale, self.angle) | ||||
|         self.screen.blit(current_image, (self.pos)) | ||||
| @ -0,0 +1,34 @@ | ||||
| import pygame | ||||
| 
 | ||||
| class SquareSpriteSheet(): | ||||
|     def __init__(self, filename, size, numberOfImages, transparency_color=(0,0,0)) -> None: | ||||
|         self.sheet = pygame.image.load(filename).convert_alpha() | ||||
|         self.size = size | ||||
|         self.numberOfImages = numberOfImages | ||||
|         self.transparency_color = transparency_color | ||||
|         self.images = [] | ||||
| 
 | ||||
|         self.load_images() | ||||
| 
 | ||||
|     def load_images(self): | ||||
|         for i in range(self.numberOfImages): | ||||
|             image = pygame.Surface((self.size, self.size)).convert_alpha() | ||||
|             image.blit(self.sheet, (0,0), ((i * self.size), 0, self.size, self.size)) | ||||
|             image.set_colorkey(self.transparency_color) | ||||
|             self.images.append(image) | ||||
| 
 | ||||
|     def get_image_by_frame(self, frame, scale=1, angle=0): | ||||
|             image = self.images[frame] | ||||
|             image = pygame.transform.scale(image, (self.size * scale, self.size * scale)) | ||||
|             image = self.rot_center(image, angle) | ||||
|             image.set_colorkey(self.transparency_color) | ||||
|             return image | ||||
| 
 | ||||
|     def rot_center(self, image, angle): | ||||
|         """rotate an image while keeping its center and size""" | ||||
|         orig_rect = image.get_rect() | ||||
|         rot_image = pygame.transform.rotate(image, angle) | ||||
|         rot_rect = orig_rect.copy() | ||||
|         rot_rect.center = rot_image.get_rect().center | ||||
|         rot_image = rot_image.subsurface(rot_rect).copy() | ||||
|         return rot_image | ||||
					Loading…
					
					
				
		Reference in new issue