# Turn and Move¶

In this example, the tank turns and moves towards where ever the user clicks the mouse.

turn_and_move.py
 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190``` ```""" Turn and Move Example """ import math import arcade SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 SCREEN_TITLE = "Turn and Move Example" # Image might not be lined up right, set this to offset IMAGE_ROTATION = 90 class Player(arcade.Sprite): """ Sprite that turns and moves """ def __init__(self): super().__init__(":resources:images/topdown_tanks/tank_green.png") # Destination point is where we are going self._destination_point = None # Max speed self.speed = 5 # Max speed we can rotate self.rot_speed = 5 @property def destination_point(self): return self._destination_point @destination_point.setter def destination_point(self, destination_point): self._destination_point = destination_point def on_update(self, delta_time: float = 1/60): """ Update the player """ # If we have no destination, don't go anywhere. if not self._destination_point: self.change_x = 0 self.change_y = 0 return # Position the start at our current location start_x = self.center_x start_y = self.center_y # Get the destination location dest_x = self._destination_point[0] dest_y = self._destination_point[1] # Do math to calculate how to get the sprite to the destination. # Calculation the angle in radians between the start points # and end points. This is the angle the player will travel. x_diff = dest_x - start_x y_diff = dest_y - start_y target_angle_radians = math.atan2(y_diff, x_diff) if target_angle_radians < 0: target_angle_radians += 2 * math.pi # What angle are we at now in radians? actual_angle_radians = math.radians(self.angle - IMAGE_ROTATION) # How fast can we rotate? rot_speed_radians = math.radians(self.rot_speed) # What is the difference between what we want, and where we are? angle_diff_radians = target_angle_radians - actual_angle_radians # Figure out if we rotate clockwise or counter-clockwise if abs(angle_diff_radians) <= rot_speed_radians: # Close enough, let's set our angle to the target actual_angle_radians = target_angle_radians clockwise = None elif angle_diff_radians > 0 and abs(angle_diff_radians) < math.pi: clockwise = False elif angle_diff_radians > 0 and abs(angle_diff_radians) >= math.pi: clockwise = True elif angle_diff_radians < 0 and abs(angle_diff_radians) < math.pi: clockwise = True else: clockwise = False # Rotate the proper direction if needed if actual_angle_radians != target_angle_radians and clockwise: actual_angle_radians -= rot_speed_radians elif actual_angle_radians != target_angle_radians: actual_angle_radians += rot_speed_radians # Keep in a range of 0 to 2pi if actual_angle_radians > 2 * math.pi: actual_angle_radians -= 2 * math.pi elif actual_angle_radians < 0: actual_angle_radians += 2 * math.pi # Convert back to degrees self.angle = math.degrees(actual_angle_radians) + IMAGE_ROTATION # Are we close to the correct angle? If so, move forward. if abs(angle_diff_radians) < math.pi / 4: self.change_x = math.cos(actual_angle_radians) * self.speed self.change_y = math.sin(actual_angle_radians) * self.speed # Fine-tune our change_x/change_y if we are really close to destination # point and just need to set to that location. traveling = False if abs(self.center_x - dest_x) < abs(self.change_x): self.center_x = dest_x else: self.center_x += self.change_x traveling = True if abs(self.center_y - dest_y) < abs(self.change_y): self.center_y = dest_y else: self.center_y += self.change_y traveling = True # If we have arrived, then cancel our destination point if not traveling: self._destination_point = None class MyGame(arcade.Window): """ Main application class. """ def __init__(self): super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, resizable=True) arcade.set_background_color(arcade.color.SAND) self.player_sprite = None # Sprite Lists self.player_list = None def setup(self): """ Set up the game variables. Call to re-start the game. """ # Sprite Lists self.player_list = arcade.SpriteList() self.player_sprite = Player() self.player_sprite.center_x = 300 self.player_sprite.center_y = 300 self.player_list.append(self.player_sprite) def on_draw(self): """ Render the screen. """ # This command should happen before we start drawing. It will clear # the screen to the background color, and erase what we drew last frame. arcade.start_render() # Call draw() on all your sprite lists below self.player_list.draw() def on_update(self, delta_time): """ All the logic to move, and the game logic goes here. """ self.player_list.on_update(delta_time) def on_mouse_press(self, x, y, button, key_modifiers): """ Called when the user presses a mouse button. """ if button == arcade.MOUSE_BUTTON_RIGHT: self.player_sprite.destination_point = x, y def main(): """ Main method """ game = MyGame() game.center_window() game.setup() arcade.run() if __name__ == "__main__": main() ```