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 191 192 | """
Turn and Move Example.
Right-click to cause the tank to move to that point.
"""
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.
self.clear()
# 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 function """
game = MyGame()
game.center_window()
game.setup()
arcade.run()
if __name__ == "__main__":
main()
|