Skip to content

Change rotation direction to clockwise #1624

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Mar 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a43a9ba
Change sprite rotation direction
einarf Mar 7, 2023
4d86f0b
ShapeElementList angle rotates clockwise
einarf Mar 7, 2023
fca5246
Reduce number of shapes
einarf Mar 7, 2023
7579071
Update asteroid smasher example
Mar 7, 2023
1ebd25e
Change rotate_point to go clockwise
Mar 7, 2023
ceb23ec
Update sprite_health
pvcraven Mar 8, 2023
ae51a4c
Fix sprite_bullets example
pvcraven Mar 8, 2023
77df1e5
Fix sprite_bullets_random example
pvcraven Mar 8, 2023
704f633
Fix sprite_bullets_periodic example
pvcraven Mar 8, 2023
37ba33e
Fix sprite_enemy_aims example
pvcraven Mar 8, 2023
931df3e
Merge branch 'rotation-direction' of https://github.com/pythonarcade/…
einarf Mar 9, 2023
ab2bbc6
Fix sprite_rotate_around_tank
Mar 9, 2023
c1efd76
Fix sprite_move_angle.py
Mar 9, 2023
1fd707b
Specify rotation direction for ShapeList
einarf Mar 11, 2023
c0631e0
docstrings: Specify rotation direction in draw_commmands
einarf Mar 11, 2023
e865a94
typo
einarf Mar 11, 2023
699215a
Update sprite examples for rotation
pvcraven Mar 11, 2023
fd64e18
Merge branch 'rotation-direction' of github.com:pythonarcade/arcade i…
pvcraven Mar 11, 2023
8d6fb62
Fix create_text_sprite
einarf Mar 11, 2023
00eb8ef
Merge branch 'rotation-direction' of https://github.com/pythonarcade/…
einarf Mar 11, 2023
63133fb
Fix text sprite test
einarf Mar 11, 2023
8130766
Update pymunk rotation
pvcraven Mar 18, 2023
aecabec
Update forward/reverse/strafe
pvcraven Mar 18, 2023
0f41127
Merge branch 'development' into rotation-direction
pvcraven Mar 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions arcade/draw_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def draw_arc_filled(center_x: float, center_y: float,
RGBA format.
:param float start_angle: start angle of the arc in degrees.
:param float end_angle: end angle of the arc in degrees.
:param float tilt_angle: angle the arc is tilted.
:param float tilt_angle: angle the arc is tilted (clockwise).
:param float num_segments: Number of line segments used to draw arc.
"""
unrotated_point_list = [(0.0, 0.0)]
Expand Down Expand Up @@ -89,7 +89,7 @@ def draw_arc_outline(center_x: float, center_y: float, width: float,
:param float start_angle: start angle of the arc in degrees.
:param float end_angle: end angle of the arc in degrees.
:param float border_width: width of line in pixels.
:param float tilt_angle: angle the arc is tilted.
:param float tilt_angle: angle the arc is tilted (clockwise).
:param int num_segments: float of triangle segments that make up this
circle. Higher is better quality, but slower render time.
"""
Expand Down Expand Up @@ -141,7 +141,7 @@ def draw_parabola_filled(start_x: float, start_y: float, end_x: float,
:param float end_x: The ending x position of the parabola
:param float height: The height of the parabola
:param Color color: The color of the parabola
:param float tilt_angle: The angle of the tilt of the parabola
:param float tilt_angle: The angle of the tilt of the parabola (clockwise)

"""
center_x = (start_x + end_x) / 2
Expand All @@ -165,7 +165,7 @@ def draw_parabola_outline(start_x: float, start_y: float, end_x: float,
:param float height: The height of the parabola
:param Color color: The color of the parabola
:param float border_width: The width of the parabola
:param float tilt_angle: The angle of the tilt of the parabola
:param float tilt_angle: The angle of the tilt of the parabola (clockwise)
"""
center_x = (start_x + end_x) / 2
center_y = start_y + height
Expand Down Expand Up @@ -217,7 +217,8 @@ def draw_circle_outline(center_x: float, center_y: float, radius: float,
:param Color color: color, specified in a list of 3 or 4 bytes in RGB or
RGBA format.
:param float border_width: Width of the circle outline in pixels.
:param float tilt_angle: Angle in degrees to tilt the circle. Useful for low segment count circles
:param float tilt_angle: Angle in degrees to tilt the circle (clockwise).
Useful for low segment count circles
:param int num_segments: Number of triangle segments that make up this
circle. Higher is better quality, but slower render time.
The default value of -1 means arcade will try to calculate a reasonable
Expand Down Expand Up @@ -247,7 +248,7 @@ def draw_ellipse_filled(center_x: float, center_y: float,
:param float height: height of the ellipse.
:param Color color: color, specified in a list of 3 or 4 bytes in RGB or
RGBA format.
:param float tilt_angle: Angle in degrees to tilt the ellipse.
:param float tilt_angle: Angle in degrees to tilt the ellipse (clockwise).
:param int num_segments: Number of triangle segments that make up this
circle. Higher is better quality, but slower render time.
The default value of -1 means arcade will try to calculate a reasonable
Expand Down Expand Up @@ -292,7 +293,7 @@ def draw_ellipse_outline(center_x: float, center_y: float,
:param Color color: color, specified in a list of 3 or 4 bytes in RGB or
RGBA format.
:param float border_width: Width of the circle outline in pixels.
:param float tilt_angle: Angle in degrees to tilt the ellipse.
:param float tilt_angle: Angle in degrees to tilt the ellipse (clockwise).
:param int num_segments: Number of triangle segments that make up this
circle. Higher is better quality, but slower render time.
The default value of -1 means arcade will try to calculate a reasonable
Expand Down Expand Up @@ -681,7 +682,7 @@ def draw_rectangle_outline(center_x: float, center_y: float, width: float,
:param Color color: color, specified in a list of 3 or 4 bytes in RGB or
RGBA format.
:param float border_width: width of the lines, in pixels.
:param float tilt_angle: rotation of the rectangle. Defaults to zero.
:param float tilt_angle: rotation of the rectangle. Defaults to zero (clockwise).
"""
i_lb = center_x - width / 2 + border_width / 2, center_y - height / 2 + border_width / 2
i_rb = center_x + width / 2 - border_width / 2, center_y - height / 2 + border_width / 2
Expand Down Expand Up @@ -759,7 +760,7 @@ def draw_rectangle_filled(center_x: float, center_y: float, width: float,
:param float height: height of the rectangle.
:param Color color: color, specified in a list of 3 or 4 bytes in RGB or
RGBA format.
:param float tilt_angle: rotation of the rectangle. Defaults to zero.
:param float tilt_angle: rotation of the rectangle (clockwise). Defaults to zero.
"""
window = get_window()
ctx = window.ctx
Expand Down Expand Up @@ -809,7 +810,7 @@ def draw_scaled_texture_rectangle(center_x: float, center_y: float,
:param int texture: identifier of texture returned from
load_texture() call
:param float scale: scale of texture
:param float angle: rotation of the rectangle. Defaults to zero.
:param float angle: rotation of the rectangle (clockwise). Defaults to zero.
:param float alpha: Transparency of image. 0 is fully transparent,
255 (default) is fully visible
"""
Expand All @@ -830,7 +831,7 @@ def draw_texture_rectangle(center_x: float, center_y: float,
:param float width: width of texture
:param float height: height of texture
:param int texture: identifier of texture returned from load_texture() call
:param float angle: rotation of the rectangle. Defaults to zero.
:param float angle: rotation of the rectangle. Defaults to zero (clockwise).
:param float alpha: Transparency of image. 0 is fully transparent, 255 (default) is visible
"""
texture.draw_sized(center_x, center_y, width, height, angle, alpha)
Expand All @@ -849,7 +850,7 @@ def draw_lrwh_rectangle_textured(bottom_left_x: float, bottom_left_y: float,
:param float width: The width of the rectangle.
:param float height: The height of the rectangle.
:param int texture: identifier of texture returned from load_texture() call
:param float angle: rotation of the rectangle. Defaults to zero.
:param float angle: rotation of the rectangle. Defaults to zero (clockwise).
:param int alpha: Transparency of image. 0 is fully transparent, 255 (default) is visible
"""

Expand All @@ -865,7 +866,7 @@ def get_pixel(x: int, y: int, components: int = 3) -> Tuple[int, ...]:
:param int x: x location
:param int y: y location
:param int components: Number of components to fetch. By default we fetch 3
3 components (RGB). 4 componets would be RGBA.
3 components (RGB). 4 components would be RGBA.
:rtype: Color
"""
# noinspection PyCallingNonCallable,PyTypeChecker
Expand Down
131 changes: 74 additions & 57 deletions arcade/examples/asteroid_smasher.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
"""
Asteroid Smasher

Shoot space rocks in this demo program created with
Python and the Arcade library.
Shoot space rocks in this demo program created with Python and the
Arcade library.

Artwork from https://kenney.nl

If Python and Arcade are installed, this example can be run from the command line with:
For a fancier example of this game, see:
https://github.com/pythonarcade/asteroids

If Python and Arcade are installed, this example can be run from
the command line with:
python -m arcade.examples.asteroid_smasher
"""
import random
Expand All @@ -15,39 +19,41 @@

from typing import cast

SCREEN_TITLE = "Asteroid Smasher"
STARTING_ASTEROID_COUNT = 3
SCALE = 0.5
OFFSCREEN_SPACE = 300

# Screen dimensions and limits
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Asteroid Smasher"
OFFSCREEN_SPACE = 300
LEFT_LIMIT = -OFFSCREEN_SPACE
RIGHT_LIMIT = SCREEN_WIDTH + OFFSCREEN_SPACE
BOTTOM_LIMIT = -OFFSCREEN_SPACE
TOP_LIMIT = SCREEN_HEIGHT + OFFSCREEN_SPACE

# Control player speed
TURN_SPEED = 3
THRUST_AMOUNT = 0.2


class TurningSprite(arcade.Sprite):
""" Sprite that sets its angle to the direction it is traveling in. """
def update(self):
""" Move the sprite """
super().update()
self.angle = math.degrees(math.atan2(self.change_y, self.change_x))
self.angle = -math.degrees(math.atan2(self.change_y, self.change_x))


class ShipSprite(arcade.Sprite):
"""
Sprite that represents our space ship.

Derives from arcade.Sprite.
"""
""" Sprite that represents our spaceship. """
def __init__(self, filename, scale):
""" Set up the space ship. """
""" Set up the spaceship. """

# Call the parent Sprite constructor
super().__init__(filename, scale=scale)

# Info on where we are going.
# Info on the space ship.
# Angle comes in automatically from the parent class.
self.thrust = 0
self.speed = 0
Expand All @@ -65,52 +71,60 @@ def respawn(self):
"""
# If we are in the middle of respawning, this is non-zero.
self.respawning = 1
self.alpha = 0
self.center_x = SCREEN_WIDTH / 2
self.center_y = SCREEN_HEIGHT / 2
self.angle = 0

def update(self):
"""
Update our position and other particulars.
"""
""" Update our position and other particulars. """

# Is the user spawning
if self.respawning:
# Increase spawn counter, setting alpha to that amount
self.respawning += 1
self.alpha = self.respawning
if self.respawning > 250:
# Once we are close enough, set alpha to 255 and clear
# respawning flag
if self.respawning > 230:
self.respawning = 0
self.alpha = 255

# Apply drag forward
if self.speed > 0:
self.speed -= self.drag
if self.speed < 0:
self.speed = 0

# Apply drag reverse
if self.speed < 0:
self.speed += self.drag
if self.speed > 0:
self.speed = 0

# Apply thrust
self.speed += self.thrust

# Enforce speed limit
if self.speed > self.max_speed:
self.speed = self.max_speed
if self.speed < -self.max_speed:
self.speed = -self.max_speed

self.change_x = -math.sin(math.radians(self.angle)) * self.speed
# Calculate movement vector based on speed/angle
self.change_x = math.sin(math.radians(self.angle)) * self.speed
self.change_y = math.cos(math.radians(self.angle)) * self.speed

# Apply movement vector
self.center_x += self.change_x
self.center_y += self.change_y

# If the ship goes off-screen, move it to the other side of the window
if self.right < 0:
self.left = SCREEN_WIDTH

if self.left > SCREEN_WIDTH:
self.right = 0

if self.bottom < 0:
self.top = SCREEN_HEIGHT

if self.top > SCREEN_HEIGHT:
self.bottom = 0

Expand Down Expand Up @@ -146,7 +160,7 @@ def __init__(self):

self.game_over = False

# Sprite lists
# Create sprite lists
self.player_sprite_list = arcade.SpriteList()
self.asteroid_list = arcade.SpriteList()
self.bullet_list = arcade.SpriteList()
Expand All @@ -157,16 +171,26 @@ def __init__(self):
self.player_sprite = None
self.lives = 3

# Sounds
# Load sounds
self.laser_sound = arcade.load_sound(":resources:sounds/hurt5.wav")
self.hit_sound1 = arcade.load_sound(":resources:sounds/explosion1.wav")
self.hit_sound2 = arcade.load_sound(":resources:sounds/explosion2.wav")
self.hit_sound3 = arcade.load_sound(":resources:sounds/hit1.wav")
self.hit_sound4 = arcade.load_sound(":resources:sounds/hit2.wav")

# Text
self.text_score = None
self.text_asteroid_count = None
# Text fields
self.text_score = arcade.Text(
f"Score: {self.score}",
start_x=10,
start_y=70,
font_size=13,
)
self.text_asteroid_count = arcade.Text(
f"Asteroid Count: {len(self.asteroid_list)}",
start_x=10,
start_y=50,
font_size=13,
)

def start_new_game(self):
""" Set up the game and initialize the variables. """
Expand Down Expand Up @@ -202,40 +226,30 @@ def start_new_game(self):
":resources:images/space_shooter/meteorGrey_big3.png",
":resources:images/space_shooter/meteorGrey_big4.png")
for i in range(STARTING_ASTEROID_COUNT):
# Pick one of four random rock images
image_no = random.randrange(4)

enemy_sprite = AsteroidSprite(image_list[image_no], scale=SCALE)
enemy_sprite.guid = "Asteroid"

# Set position
enemy_sprite.center_y = random.randrange(BOTTOM_LIMIT, TOP_LIMIT)
enemy_sprite.center_x = random.randrange(LEFT_LIMIT, RIGHT_LIMIT)

# Set speed / rotation
enemy_sprite.change_x = random.random() * 2 - 1
enemy_sprite.change_y = random.random() * 2 - 1

enemy_sprite.change_angle = (random.random() - 0.5) * 2

enemy_sprite.size = 4
self.asteroid_list.append(enemy_sprite)

# Create new text objects with initial values
self.text_score = arcade.Text(
f"Score: {self.score}",
start_x=10,
start_y=70,
font_size=13,
)
self.text_asteroid_count = arcade.Text(
f"Asteroid Count: {len(self.asteroid_list)}",
start_x=10,
start_y=50,
font_size=13,
)
self.text_score.text = f"Score: {self.score}"
self.text_asteroid_count.text = f"Asteroid Count: {len(self.asteroid_list)}"

def on_draw(self):
"""
Render the screen.
"""
""" Render the screen """

# This command has to happen before we start drawing
# Clear the screen before we start drawing
self.clear()

# Draw all the sprites.
Expand All @@ -254,31 +268,34 @@ def on_key_press(self, symbol, modifiers):
if not self.player_sprite.respawning and symbol == arcade.key.SPACE:
bullet_sprite = TurningSprite(":resources:images/space_shooter/laserBlue01.png",
scale=SCALE)
bullet_sprite.guid = "Bullet"

# Set bullet vector
bullet_speed = 13
bullet_sprite.change_y = \
math.cos(math.radians(self.player_sprite.angle)) * bullet_speed
bullet_sprite.change_x = \
-math.sin(math.radians(self.player_sprite.angle)) \
* bullet_speed
angle_radians = math.radians(self.player_sprite.angle)
bullet_sprite.change_y = math.cos(angle_radians) * bullet_speed
bullet_sprite.change_x = math.sin(angle_radians) * bullet_speed

# Set bullet position
bullet_sprite.center_x = self.player_sprite.center_x
bullet_sprite.center_y = self.player_sprite.center_y
bullet_sprite.update()

# Add to our sprite list
self.bullet_list.append(bullet_sprite)

# Go ahead and move it a frame
bullet_sprite.update()

# Pew pew
arcade.play_sound(self.laser_sound, speed=random.random() * 3 + 0.5)

if symbol == arcade.key.LEFT:
self.player_sprite.change_angle = 3
self.player_sprite.change_angle = -TURN_SPEED
elif symbol == arcade.key.RIGHT:
self.player_sprite.change_angle = -3
self.player_sprite.change_angle = TURN_SPEED
elif symbol == arcade.key.UP:
self.player_sprite.thrust = 0.15
self.player_sprite.thrust = THRUST_AMOUNT
elif symbol == arcade.key.DOWN:
self.player_sprite.thrust = -.2
self.player_sprite.thrust = -THRUST_AMOUNT

def on_key_release(self, symbol, modifiers):
""" Called whenever a key is released. """
Expand Down
Loading