Skip to content

Commit

Permalink
Merge #456
Browse files Browse the repository at this point in the history
456: (WIP) TargetSprite r=pathunstrom a=serin-delaunay

Class `TargetSprite` with parameters `target` and `speed`. Moves towards target at the given speed, and stops there. Will resolve #382.

Co-authored-by: Serin Delaunay <serin.delaunay@gmail.com>
  • Loading branch information
bors[bot] and serin-delaunay authored May 7, 2020
2 parents b4569e4 + 9a30bce commit 04888d5
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ Halle Jones|HJones@aliacy.com||
[Arul Prabakaran](https://github.com/arulprabakaran) | [arul.prabakaran@gmail.com](arul.prabakaran@gmail.com) | [arulpraba](https://twitter.com/arulpraba)
[Calvin Spealman](https://github.com/ironfroggy) | [ironfroggy@gmail.com](ironfroggy@gmail.com) | [@ironfroggy](https://twitter.com/ironfroggy)
[Sanket Dasgupta](https://github.com/SanketDG) | [sanketdasgupta@gmail.com](sanketdasgupta@gmail.com) | [@SanketDG](https://twitter.com/SanketDG)
[Serin Delaunay](https://github.com/serin-delaunay) | | [SerinDelaunay](https://twitter.com/SerinDelaunay)
43 changes: 43 additions & 0 deletions ppb/features/default_sprites.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import ppb
import math


class TargetSprite(ppb.Sprite):
"""Sprite that moves to a given target.
:param target: Vector that the sprite moves towards.
:param speed: Distance per second that the sprite travels with linear motion.
:param exponential_speed: Fraction of the distance to the target that the sprite travels
per second with exponential motion. Should normally be in the range [0.0, 1.0].
:param max_speed: Maximum distance per second that the sprite can travel.
:param min_speed: Minimum distance per second that the sprite travels when not in range of the target.
"""
target = ppb.Vector(0, 0)
speed = 1.0
exponential_speed = 0.0
max_speed = math.inf
min_speed = -math.inf

def on_update(self, update_event, signal):
if self.max_speed < self.min_speed:
raise ValueError("TargetSprite maximum speed cannot be less than minimum speed.")
offset = self.target - self.position
distance_to_target = offset.length
max_distance = self.max_speed * update_event.time_delta
min_distance = self.min_speed * update_event.time_delta
linear_distance = self.speed * update_event.time_delta
exponential_distance = distance_to_target * self._exponential_decay(update_event.time_delta)
total_distance = linear_distance + exponential_distance
total_distance = min(total_distance, max_distance)
total_distance = max(total_distance, min_distance)
if distance_to_target <= total_distance:
self.position = self.target
else:
direction = offset.normalize()
self.position += direction * total_distance

def _exponential_decay(self, time_delta):
decay_rate = 1. - self.exponential_speed
remaining = decay_rate ** time_delta
decay_amount = 1. - remaining
return decay_amount
44 changes: 44 additions & 0 deletions tests/test_default_sprites.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import unittest
import ppb
from ppb import Vector
from ppb.features.default_sprites import TargetSprite


def test_target_sprite_linear():
target_sprite = TargetSprite()
target_sprite.target = Vector(3, 4)
target_sprite.speed = 5.0
target_sprite.on_update(ppb.events.Update(0.2), lambda x: None)

assert target_sprite.position.isclose((0.6, 0.8))


def test_target_sprite_exponential():
target_sprite = TargetSprite()
target_sprite.target = Vector(3, -4)
target_sprite.speed = 0.0
target_sprite.exponential_speed = 0.5
target_sprite.on_update(ppb.events.Update(2.0), lambda x: None)

assert target_sprite.position.isclose((2.25, -3.0))


def test_target_sprite_max_speed():
target_sprite = TargetSprite()
target_sprite.target = Vector(-3, 4)
target_sprite.speed = 500.
target_sprite.exponential_speed = 0.99
target_sprite.max_speed = 1.0
target_sprite.on_update(ppb.events.Update(2.0), lambda x: None)

assert target_sprite.position.isclose((-1.2, 1.6))


def test_target_sprite_min_speed():
target_sprite = TargetSprite()
target_sprite.target = Vector(-3, -4)
target_sprite.speed = 0.0
target_sprite.min_speed = 2.0
target_sprite.on_update(ppb.events.Update(1.0), lambda x: None)

assert target_sprite.position.isclose((-1.2, -1.6))

0 comments on commit 04888d5

Please sign in to comment.