Skip to content

Commit

Permalink
Merge pull request #66 from ThalesGroup/65-add-bounded-random-asteroi…
Browse files Browse the repository at this point in the history
…d-splits

Added random asteroid split option into game settings, updated versio…
  • Loading branch information
TimArnettThales authored Jul 3, 2024
2 parents 0a481c8 + 02d599a commit 47b535b
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [2.1.7] - 3 July 2024

- Added optional Boolean setting `random_ast_splits` for game object instantiation. If `True`, left and right asteroid
child asteroid vectors will be be random within a bounded range about the main child asteroid vector. By default
is set to `False`.

## [2.1.6] - 2 July 2024

- Changed `stop_if_no_ammo` condition to also check mines. Also changed condition such that sum of mines and bullets
Expand Down
6 changes: 4 additions & 2 deletions examples/scenario_test_multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@
map_size=(1000, 800),
time_limit=60,
ammo_limit_multiplier=0,
stop_if_no_ammo=False)
stop_if_no_ammo=False,
seed=8)

# Define Game Settings
game_settings = {'perf_tracker': True,
'graphics_type': GraphicsType.Tkinter,
'realtime_multiplier': 1,
'graphics_obj': None,
'frequency': 30}
'frequency': 60,
'random_ast_splits': True}

game = KesslerGame(settings=game_settings) # Use this to visualize the game scenario
# game = TrainerEnvironment(settings=game_settings) # Use this for max-speed, no-graphics simulation
Expand Down
2 changes: 1 addition & 1 deletion src/kesslergame/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '2.1.6'
__version__ = '2.1.7'
13 changes: 8 additions & 5 deletions src/kesslergame/asteroid.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def update(self, delta_time: float = 1/30) -> None:
self.position = (self.position[0] + self.velocity[0] * delta_time, self.position[1] + self.velocity[1] * delta_time)
self.angle += delta_time * self.turnrate

def destruct(self, impactor: Union['Bullet', 'Mine', 'Ship']) -> list['Asteroid']:
def destruct(self, impactor: Union['Bullet', 'Mine', 'Ship'], random_ast_split: bool) -> list['Asteroid']:
""" Spawn child asteroids"""

if self.size != 1:
Expand All @@ -107,7 +107,7 @@ def destruct(self, impactor: Union['Bullet', 'Mine', 'Ship']) -> list['Asteroid'
v = math.sqrt(vfx*vfx + vfy*vfy)
# Split angle is the angle off of the new velocity vector for the two asteroids to the sides, the center child
# asteroid continues on the new velocity path
split_angle = 15.0
split_angle_bound = 30.0
else:
vfx = self.vx
vfy = self.vy
Expand All @@ -117,7 +117,7 @@ def destruct(self, impactor: Union['Bullet', 'Mine', 'Ship']) -> list['Asteroid'
v = math.sqrt(vfx*vfx + vfy*vfy + a*a)
# Split angle is the angle off of the new velocity vector for the two asteroids to the sides, the center child
# asteroid continues on the new velocity path
split_angle = 120.0
split_angle_bound = 120.0
else:
# Calculating new velocity vector of asteroid children based on bullet-asteroid collision/momentum
# Currently collisions are considered perfectly inelastic i.e. the bullet is absorbed by the asteroid
Expand All @@ -135,10 +135,13 @@ def destruct(self, impactor: Union['Bullet', 'Mine', 'Ship']) -> list['Asteroid'
v = math.sqrt(vfx*vfx + vfy*vfy)
# Split angle is the angle off of the new velocity vector for the two asteroids to the sides, the center child
# asteroid continues on the new velocity path
split_angle = 15.0
split_angle_bound = 30.0
# Calculate angle of center asteroid for split (degrees)
theta = math.degrees(math.atan2(vfy, vfx))
angles = [theta + split_angle, theta, theta - split_angle]
if random_ast_split:
angles = [theta + split_angle_bound*random.random(), theta, theta - split_angle_bound*random.random()]
else:
angles = [theta + split_angle_bound/2.0, theta, theta - split_angle_bound/2.0]

return [Asteroid(position=self.position, size=self.size-1, speed=v, angle=angle) for angle in angles]

Expand Down
7 changes: 4 additions & 3 deletions src/kesslergame/kessler_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __init__(self, settings: Optional[Dict[str, Any]] = None) -> None:
self.graphics_obj: Optional[KesslerGraphics] = settings.get("graphics_obj", None)
self.realtime_multiplier: float = settings.get("realtime_multiplier", 0 if self.graphics_type==GraphicsType.NoGraphics else 1)
self.time_limit: float = settings.get("time_limit", float("inf"))
self.random_ast_splits = settings.get("random_ast_splits", False)

# UI settings
default_ui = {'ships': True, 'lives_remaining': True, 'accuracy': True,
Expand Down Expand Up @@ -209,7 +210,7 @@ def run(self, scenario: Scenario, controllers: List[KesslerController]) -> Tuple
bullet.destruct()
bullet_remove_idxs.append(idx_bul)
# Asteroid destruct function and mark for removal
asteroids.extend(asteroid.destruct(impactor=bullet))
asteroids.extend(asteroid.destruct(impactor=bullet, random_ast_split=self.random_ast_splits))
asteroid_remove_idxs.add(idx_ast)
# Stop checking this bullet
break
Expand All @@ -230,7 +231,7 @@ def run(self, scenario: Scenario, controllers: List[KesslerController]) -> Tuple
if dx * dx + dy * dy <= radius_sum * radius_sum:
mine.owner.asteroids_hit += 1
mine.owner.mines_hit += 1
new_asteroids.extend(asteroid.destruct(impactor=mine))
new_asteroids.extend(asteroid.destruct(impactor=mine, random_ast_split=self.random_ast_splits))
asteroid_remove_idxs.add(idx_ast)
for ship in liveships:
if not ship.is_respawning:
Expand Down Expand Up @@ -263,7 +264,7 @@ def run(self, scenario: Scenario, controllers: List[KesslerController]) -> Tuple
# Most of the time no collision occurs, so use early exit to optimize collision check
if abs(dx) <= radius_sum and abs(dy) <= radius_sum and dx * dx + dy * dy <= radius_sum * radius_sum:
# Asteroid destruct function and mark for removal
asteroids.extend(asteroid.destruct(impactor=ship))
asteroids.extend(asteroid.destruct(impactor=ship, random_ast_split=self.random_ast_splits))
asteroid_remove_idxs.add(idx_ast)
# Ship destruct function. Add one to asteroids_hit
ship.asteroids_hit += 1
Expand Down

0 comments on commit 47b535b

Please sign in to comment.