bastd.game.easteregghunt
Provides an easter egg hunt game.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Provides an easter egg hunt game.""" 4 5# ba_meta require api 7 6# (see https://ballistica.net/wiki/meta-tag-system) 7 8from __future__ import annotations 9 10import random 11from typing import TYPE_CHECKING 12 13import ba 14from bastd.actor.bomb import Bomb 15from bastd.actor.playerspaz import PlayerSpaz 16from bastd.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage 17from bastd.actor.onscreencountdown import OnScreenCountdown 18from bastd.actor.scoreboard import Scoreboard 19from bastd.actor.respawnicon import RespawnIcon 20from bastd.gameutils import SharedObjects 21 22if TYPE_CHECKING: 23 from typing import Any 24 25 26class Player(ba.Player['Team']): 27 """Our player type for this game.""" 28 29 def __init__(self) -> None: 30 self.respawn_timer: ba.Timer | None = None 31 self.respawn_icon: RespawnIcon | None = None 32 33 34class Team(ba.Team[Player]): 35 """Our team type for this game.""" 36 37 def __init__(self) -> None: 38 self.score = 0 39 40 41# ba_meta export game 42class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): 43 """A game where score is based on collecting eggs.""" 44 45 name = 'Easter Egg Hunt' 46 description = 'Gather eggs!' 47 available_settings = [ 48 ba.BoolSetting('Pro Mode', default=False), 49 ba.BoolSetting('Epic Mode', default=False), 50 ] 51 scoreconfig = ba.ScoreConfig(label='Score', scoretype=ba.ScoreType.POINTS) 52 53 # We're currently hard-coded for one map. 54 @classmethod 55 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 56 return ['Tower D'] 57 58 # We support teams, free-for-all, and co-op sessions. 59 @classmethod 60 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 61 return ( 62 issubclass(sessiontype, ba.CoopSession) 63 or issubclass(sessiontype, ba.DualTeamSession) 64 or issubclass(sessiontype, ba.FreeForAllSession) 65 ) 66 67 def __init__(self, settings: dict): 68 super().__init__(settings) 69 shared = SharedObjects.get() 70 self._last_player_death_time = None 71 self._scoreboard = Scoreboard() 72 self.egg_model = ba.getmodel('egg') 73 self.egg_tex_1 = ba.gettexture('eggTex1') 74 self.egg_tex_2 = ba.gettexture('eggTex2') 75 self.egg_tex_3 = ba.gettexture('eggTex3') 76 self._collect_sound = ba.getsound('powerup01') 77 self._pro_mode = settings.get('Pro Mode', False) 78 self._epic_mode = settings.get('Epic Mode', False) 79 self._max_eggs = 1.0 80 self.egg_material = ba.Material() 81 self.egg_material.add_actions( 82 conditions=('they_have_material', shared.player_material), 83 actions=(('call', 'at_connect', self._on_egg_player_collide),), 84 ) 85 self._eggs: list[Egg] = [] 86 self._update_timer: ba.Timer | None = None 87 self._countdown: OnScreenCountdown | None = None 88 self._bots: SpazBotSet | None = None 89 90 # Base class overrides 91 self.slow_motion = self._epic_mode 92 self.default_music = ( 93 ba.MusicType.EPIC if self._epic_mode else ba.MusicType.FORWARD_MARCH 94 ) 95 96 def on_team_join(self, team: Team) -> None: 97 if self.has_begun(): 98 self._update_scoreboard() 99 100 # Called when our game actually starts. 101 def on_begin(self) -> None: 102 from bastd.maps import TowerD 103 104 # There's a player-wall on the tower-d level to prevent 105 # players from getting up on the stairs.. we wanna kill that. 106 gamemap = self.map 107 assert isinstance(gamemap, TowerD) 108 gamemap.player_wall.delete() 109 super().on_begin() 110 self._update_scoreboard() 111 self._update_timer = ba.Timer(0.25, self._update, repeat=True) 112 self._countdown = OnScreenCountdown(60, endcall=self.end_game) 113 ba.timer(4.0, self._countdown.start) 114 self._bots = SpazBotSet() 115 116 # Spawn evil bunny in co-op only. 117 if isinstance(self.session, ba.CoopSession) and self._pro_mode: 118 self._spawn_evil_bunny() 119 120 # Overriding the default character spawning. 121 def spawn_player(self, player: Player) -> ba.Actor: 122 spaz = self.spawn_player_spaz(player) 123 spaz.connect_controls_to_player() 124 return spaz 125 126 def _spawn_evil_bunny(self) -> None: 127 assert self._bots is not None 128 self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0) 129 130 def _on_egg_player_collide(self) -> None: 131 if self.has_ended(): 132 return 133 collision = ba.getcollision() 134 135 # Be defensive here; we could be hitting the corpse of a player 136 # who just left/etc. 137 try: 138 egg = collision.sourcenode.getdelegate(Egg, True) 139 player = collision.opposingnode.getdelegate( 140 PlayerSpaz, True 141 ).getplayer(Player, True) 142 except ba.NotFoundError: 143 return 144 145 player.team.score += 1 146 147 # Displays a +1 (and adds to individual player score in 148 # teams mode). 149 self.stats.player_scored(player, 1, screenmessage=False) 150 if self._max_eggs < 5: 151 self._max_eggs += 1.0 152 elif self._max_eggs < 10: 153 self._max_eggs += 0.5 154 elif self._max_eggs < 30: 155 self._max_eggs += 0.3 156 self._update_scoreboard() 157 ba.playsound(self._collect_sound, 0.5, position=egg.node.position) 158 159 # Create a flash. 160 light = ba.newnode( 161 'light', 162 attrs={ 163 'position': egg.node.position, 164 'height_attenuated': False, 165 'radius': 0.1, 166 'color': (1, 1, 0), 167 }, 168 ) 169 ba.animate(light, 'intensity', {0: 0, 0.1: 1.0, 0.2: 0}, loop=False) 170 ba.timer(0.200, light.delete) 171 egg.handlemessage(ba.DieMessage()) 172 173 def _update(self) -> None: 174 # Misc. periodic updating. 175 xpos = random.uniform(-7.1, 6.0) 176 ypos = random.uniform(3.5, 3.5) 177 zpos = random.uniform(-8.2, 3.7) 178 179 # Prune dead eggs from our list. 180 self._eggs = [e for e in self._eggs if e] 181 182 # Spawn more eggs if we've got space. 183 if len(self._eggs) < int(self._max_eggs): 184 185 # Occasionally spawn a land-mine in addition. 186 if self._pro_mode and random.random() < 0.25: 187 mine = Bomb( 188 position=(xpos, ypos, zpos), bomb_type='land_mine' 189 ).autoretain() 190 mine.arm() 191 else: 192 self._eggs.append(Egg(position=(xpos, ypos, zpos))) 193 194 # Various high-level game events come through this method. 195 def handlemessage(self, msg: Any) -> Any: 196 197 # Respawn dead players. 198 if isinstance(msg, ba.PlayerDiedMessage): 199 # Augment standard behavior. 200 super().handlemessage(msg) 201 202 # Respawn them shortly. 203 player = msg.getplayer(Player) 204 assert self.initialplayerinfos is not None 205 respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 206 player.respawn_timer = ba.Timer( 207 respawn_time, ba.Call(self.spawn_player_if_exists, player) 208 ) 209 player.respawn_icon = RespawnIcon(player, respawn_time) 210 211 # Whenever our evil bunny dies, respawn him and spew some eggs. 212 elif isinstance(msg, SpazBotDiedMessage): 213 self._spawn_evil_bunny() 214 assert msg.spazbot.node 215 pos = msg.spazbot.node.position 216 for _i in range(6): 217 spread = 0.4 218 self._eggs.append( 219 Egg( 220 position=( 221 pos[0] + random.uniform(-spread, spread), 222 pos[1] + random.uniform(-spread, spread), 223 pos[2] + random.uniform(-spread, spread), 224 ) 225 ) 226 ) 227 else: 228 # Default handler. 229 return super().handlemessage(msg) 230 return None 231 232 def _update_scoreboard(self) -> None: 233 for team in self.teams: 234 self._scoreboard.set_team_value(team, team.score) 235 236 def end_game(self) -> None: 237 results = ba.GameResults() 238 for team in self.teams: 239 results.set_team_score(team, team.score) 240 self.end(results) 241 242 243class Egg(ba.Actor): 244 """A lovely egg that can be picked up for points.""" 245 246 def __init__(self, position: tuple[float, float, float] = (0.0, 1.0, 0.0)): 247 super().__init__() 248 activity = self.activity 249 assert isinstance(activity, EasterEggHuntGame) 250 shared = SharedObjects.get() 251 252 # Spawn just above the provided point. 253 self._spawn_pos = (position[0], position[1] + 1.0, position[2]) 254 ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[ 255 random.randrange(3) 256 ] 257 mats = [shared.object_material, activity.egg_material] 258 self.node = ba.newnode( 259 'prop', 260 delegate=self, 261 attrs={ 262 'model': activity.egg_model, 263 'color_texture': ctex, 264 'body': 'capsule', 265 'reflection': 'soft', 266 'model_scale': 0.5, 267 'body_scale': 0.6, 268 'density': 4.0, 269 'reflection_scale': [0.15], 270 'shadow_size': 0.6, 271 'position': self._spawn_pos, 272 'materials': mats, 273 }, 274 ) 275 276 def exists(self) -> bool: 277 return bool(self.node) 278 279 def handlemessage(self, msg: Any) -> Any: 280 if isinstance(msg, ba.DieMessage): 281 if self.node: 282 self.node.delete() 283 elif isinstance(msg, ba.HitMessage): 284 if self.node: 285 assert msg.force_direction is not None 286 self.node.handlemessage( 287 'impulse', 288 msg.pos[0], 289 msg.pos[1], 290 msg.pos[2], 291 msg.velocity[0], 292 msg.velocity[1], 293 msg.velocity[2], 294 1.0 * msg.magnitude, 295 1.0 * msg.velocity_magnitude, 296 msg.radius, 297 0, 298 msg.force_direction[0], 299 msg.force_direction[1], 300 msg.force_direction[2], 301 ) 302 else: 303 super().handlemessage(msg)
27class Player(ba.Player['Team']): 28 """Our player type for this game.""" 29 30 def __init__(self) -> None: 31 self.respawn_timer: ba.Timer | None = None 32 self.respawn_icon: RespawnIcon | None = None
Our player type for this game.
Inherited Members
- ba._player.Player
- actor
- on_expire
- team
- customdata
- sessionplayer
- node
- position
- exists
- getname
- is_alive
- get_icon
- assigninput
- resetinput
35class Team(ba.Team[Player]): 36 """Our team type for this game.""" 37 38 def __init__(self) -> None: 39 self.score = 0
Our team type for this game.
Inherited Members
- ba._team.Team
- manual_init
- customdata
- on_expire
- sessionteam
43class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): 44 """A game where score is based on collecting eggs.""" 45 46 name = 'Easter Egg Hunt' 47 description = 'Gather eggs!' 48 available_settings = [ 49 ba.BoolSetting('Pro Mode', default=False), 50 ba.BoolSetting('Epic Mode', default=False), 51 ] 52 scoreconfig = ba.ScoreConfig(label='Score', scoretype=ba.ScoreType.POINTS) 53 54 # We're currently hard-coded for one map. 55 @classmethod 56 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 57 return ['Tower D'] 58 59 # We support teams, free-for-all, and co-op sessions. 60 @classmethod 61 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 62 return ( 63 issubclass(sessiontype, ba.CoopSession) 64 or issubclass(sessiontype, ba.DualTeamSession) 65 or issubclass(sessiontype, ba.FreeForAllSession) 66 ) 67 68 def __init__(self, settings: dict): 69 super().__init__(settings) 70 shared = SharedObjects.get() 71 self._last_player_death_time = None 72 self._scoreboard = Scoreboard() 73 self.egg_model = ba.getmodel('egg') 74 self.egg_tex_1 = ba.gettexture('eggTex1') 75 self.egg_tex_2 = ba.gettexture('eggTex2') 76 self.egg_tex_3 = ba.gettexture('eggTex3') 77 self._collect_sound = ba.getsound('powerup01') 78 self._pro_mode = settings.get('Pro Mode', False) 79 self._epic_mode = settings.get('Epic Mode', False) 80 self._max_eggs = 1.0 81 self.egg_material = ba.Material() 82 self.egg_material.add_actions( 83 conditions=('they_have_material', shared.player_material), 84 actions=(('call', 'at_connect', self._on_egg_player_collide),), 85 ) 86 self._eggs: list[Egg] = [] 87 self._update_timer: ba.Timer | None = None 88 self._countdown: OnScreenCountdown | None = None 89 self._bots: SpazBotSet | None = None 90 91 # Base class overrides 92 self.slow_motion = self._epic_mode 93 self.default_music = ( 94 ba.MusicType.EPIC if self._epic_mode else ba.MusicType.FORWARD_MARCH 95 ) 96 97 def on_team_join(self, team: Team) -> None: 98 if self.has_begun(): 99 self._update_scoreboard() 100 101 # Called when our game actually starts. 102 def on_begin(self) -> None: 103 from bastd.maps import TowerD 104 105 # There's a player-wall on the tower-d level to prevent 106 # players from getting up on the stairs.. we wanna kill that. 107 gamemap = self.map 108 assert isinstance(gamemap, TowerD) 109 gamemap.player_wall.delete() 110 super().on_begin() 111 self._update_scoreboard() 112 self._update_timer = ba.Timer(0.25, self._update, repeat=True) 113 self._countdown = OnScreenCountdown(60, endcall=self.end_game) 114 ba.timer(4.0, self._countdown.start) 115 self._bots = SpazBotSet() 116 117 # Spawn evil bunny in co-op only. 118 if isinstance(self.session, ba.CoopSession) and self._pro_mode: 119 self._spawn_evil_bunny() 120 121 # Overriding the default character spawning. 122 def spawn_player(self, player: Player) -> ba.Actor: 123 spaz = self.spawn_player_spaz(player) 124 spaz.connect_controls_to_player() 125 return spaz 126 127 def _spawn_evil_bunny(self) -> None: 128 assert self._bots is not None 129 self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0) 130 131 def _on_egg_player_collide(self) -> None: 132 if self.has_ended(): 133 return 134 collision = ba.getcollision() 135 136 # Be defensive here; we could be hitting the corpse of a player 137 # who just left/etc. 138 try: 139 egg = collision.sourcenode.getdelegate(Egg, True) 140 player = collision.opposingnode.getdelegate( 141 PlayerSpaz, True 142 ).getplayer(Player, True) 143 except ba.NotFoundError: 144 return 145 146 player.team.score += 1 147 148 # Displays a +1 (and adds to individual player score in 149 # teams mode). 150 self.stats.player_scored(player, 1, screenmessage=False) 151 if self._max_eggs < 5: 152 self._max_eggs += 1.0 153 elif self._max_eggs < 10: 154 self._max_eggs += 0.5 155 elif self._max_eggs < 30: 156 self._max_eggs += 0.3 157 self._update_scoreboard() 158 ba.playsound(self._collect_sound, 0.5, position=egg.node.position) 159 160 # Create a flash. 161 light = ba.newnode( 162 'light', 163 attrs={ 164 'position': egg.node.position, 165 'height_attenuated': False, 166 'radius': 0.1, 167 'color': (1, 1, 0), 168 }, 169 ) 170 ba.animate(light, 'intensity', {0: 0, 0.1: 1.0, 0.2: 0}, loop=False) 171 ba.timer(0.200, light.delete) 172 egg.handlemessage(ba.DieMessage()) 173 174 def _update(self) -> None: 175 # Misc. periodic updating. 176 xpos = random.uniform(-7.1, 6.0) 177 ypos = random.uniform(3.5, 3.5) 178 zpos = random.uniform(-8.2, 3.7) 179 180 # Prune dead eggs from our list. 181 self._eggs = [e for e in self._eggs if e] 182 183 # Spawn more eggs if we've got space. 184 if len(self._eggs) < int(self._max_eggs): 185 186 # Occasionally spawn a land-mine in addition. 187 if self._pro_mode and random.random() < 0.25: 188 mine = Bomb( 189 position=(xpos, ypos, zpos), bomb_type='land_mine' 190 ).autoretain() 191 mine.arm() 192 else: 193 self._eggs.append(Egg(position=(xpos, ypos, zpos))) 194 195 # Various high-level game events come through this method. 196 def handlemessage(self, msg: Any) -> Any: 197 198 # Respawn dead players. 199 if isinstance(msg, ba.PlayerDiedMessage): 200 # Augment standard behavior. 201 super().handlemessage(msg) 202 203 # Respawn them shortly. 204 player = msg.getplayer(Player) 205 assert self.initialplayerinfos is not None 206 respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 207 player.respawn_timer = ba.Timer( 208 respawn_time, ba.Call(self.spawn_player_if_exists, player) 209 ) 210 player.respawn_icon = RespawnIcon(player, respawn_time) 211 212 # Whenever our evil bunny dies, respawn him and spew some eggs. 213 elif isinstance(msg, SpazBotDiedMessage): 214 self._spawn_evil_bunny() 215 assert msg.spazbot.node 216 pos = msg.spazbot.node.position 217 for _i in range(6): 218 spread = 0.4 219 self._eggs.append( 220 Egg( 221 position=( 222 pos[0] + random.uniform(-spread, spread), 223 pos[1] + random.uniform(-spread, spread), 224 pos[2] + random.uniform(-spread, spread), 225 ) 226 ) 227 ) 228 else: 229 # Default handler. 230 return super().handlemessage(msg) 231 return None 232 233 def _update_scoreboard(self) -> None: 234 for team in self.teams: 235 self._scoreboard.set_team_value(team, team.score) 236 237 def end_game(self) -> None: 238 results = ba.GameResults() 239 for team in self.teams: 240 results.set_team_score(team, team.score) 241 self.end(results)
A game where score is based on collecting eggs.
68 def __init__(self, settings: dict): 69 super().__init__(settings) 70 shared = SharedObjects.get() 71 self._last_player_death_time = None 72 self._scoreboard = Scoreboard() 73 self.egg_model = ba.getmodel('egg') 74 self.egg_tex_1 = ba.gettexture('eggTex1') 75 self.egg_tex_2 = ba.gettexture('eggTex2') 76 self.egg_tex_3 = ba.gettexture('eggTex3') 77 self._collect_sound = ba.getsound('powerup01') 78 self._pro_mode = settings.get('Pro Mode', False) 79 self._epic_mode = settings.get('Epic Mode', False) 80 self._max_eggs = 1.0 81 self.egg_material = ba.Material() 82 self.egg_material.add_actions( 83 conditions=('they_have_material', shared.player_material), 84 actions=(('call', 'at_connect', self._on_egg_player_collide),), 85 ) 86 self._eggs: list[Egg] = [] 87 self._update_timer: ba.Timer | None = None 88 self._countdown: OnScreenCountdown | None = None 89 self._bots: SpazBotSet | None = None 90 91 # Base class overrides 92 self.slow_motion = self._epic_mode 93 self.default_music = ( 94 ba.MusicType.EPIC if self._epic_mode else ba.MusicType.FORWARD_MARCH 95 )
Instantiate the Activity.
55 @classmethod 56 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 57 return ['Tower D']
Called by the default ba.GameActivity.create_settings_ui() implementation; should return a list of map names valid for this game-type for the given ba.Session type.
60 @classmethod 61 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 62 return ( 63 issubclass(sessiontype, ba.CoopSession) 64 or issubclass(sessiontype, ba.DualTeamSession) 65 or issubclass(sessiontype, ba.FreeForAllSession) 66 )
Class method override; returns True for ba.DualTeamSessions and ba.FreeForAllSessions; False otherwise.
Called when a new ba.Team joins the Activity.
(including the initial set of Teams)
102 def on_begin(self) -> None: 103 from bastd.maps import TowerD 104 105 # There's a player-wall on the tower-d level to prevent 106 # players from getting up on the stairs.. we wanna kill that. 107 gamemap = self.map 108 assert isinstance(gamemap, TowerD) 109 gamemap.player_wall.delete() 110 super().on_begin() 111 self._update_scoreboard() 112 self._update_timer = ba.Timer(0.25, self._update, repeat=True) 113 self._countdown = OnScreenCountdown(60, endcall=self.end_game) 114 ba.timer(4.0, self._countdown.start) 115 self._bots = SpazBotSet() 116 117 # Spawn evil bunny in co-op only. 118 if isinstance(self.session, ba.CoopSession) and self._pro_mode: 119 self._spawn_evil_bunny()
Called once the previous ba.Activity has finished transitioning out.
At this point the activity's initial players and teams are filled in and it should begin its actual game logic.
122 def spawn_player(self, player: Player) -> ba.Actor: 123 spaz = self.spawn_player_spaz(player) 124 spaz.connect_controls_to_player() 125 return spaz
Spawn something for the provided ba.Player.
The default implementation simply calls spawn_player_spaz().
196 def handlemessage(self, msg: Any) -> Any: 197 198 # Respawn dead players. 199 if isinstance(msg, ba.PlayerDiedMessage): 200 # Augment standard behavior. 201 super().handlemessage(msg) 202 203 # Respawn them shortly. 204 player = msg.getplayer(Player) 205 assert self.initialplayerinfos is not None 206 respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 207 player.respawn_timer = ba.Timer( 208 respawn_time, ba.Call(self.spawn_player_if_exists, player) 209 ) 210 player.respawn_icon = RespawnIcon(player, respawn_time) 211 212 # Whenever our evil bunny dies, respawn him and spew some eggs. 213 elif isinstance(msg, SpazBotDiedMessage): 214 self._spawn_evil_bunny() 215 assert msg.spazbot.node 216 pos = msg.spazbot.node.position 217 for _i in range(6): 218 spread = 0.4 219 self._eggs.append( 220 Egg( 221 position=( 222 pos[0] + random.uniform(-spread, spread), 223 pos[1] + random.uniform(-spread, spread), 224 pos[2] + random.uniform(-spread, spread), 225 ) 226 ) 227 ) 228 else: 229 # Default handler. 230 return super().handlemessage(msg) 231 return None
General message handling; can be passed any message object.
237 def end_game(self) -> None: 238 results = ba.GameResults() 239 for team in self.teams: 240 results.set_team_score(team, team.score) 241 self.end(results)
Tell the game to wrap up and call ba.Activity.end() immediately.
This method should be overridden by subclasses. A game should always be prepared to end and deliver results, even if there is no 'winner' yet; this way things like the standard time-limit (ba.GameActivity.setup_standard_time_limit()) will work with the game.
Inherited Members
- ba._teamgame.TeamGameActivity
- on_transition_in
- spawn_player_spaz
- end
- ba._gameactivity.GameActivity
- allow_pausing
- allow_kick_idle_players
- create_settings_ui
- getscoreconfig
- getname
- get_display_string
- get_team_display_string
- get_description
- get_description_display_string
- get_available_settings
- get_settings_display_string
- map
- get_instance_display_string
- get_instance_scoreboard_display_string
- get_instance_description
- get_instance_description_short
- on_continue
- is_waiting_for_continue
- continue_or_end_game
- on_player_join
- respawn_player
- spawn_player_if_exists
- setup_standard_powerup_drops
- setup_standard_time_limit
- show_zoom_message
- ba._activity.Activity
- settings_raw
- teams
- players
- announce_player_deaths
- is_joining_activity
- use_fixed_vr_overlay
- inherits_slow_motion
- inherits_music
- inherits_vr_camera_offset
- inherits_vr_overlay_center
- inherits_tint
- allow_mid_activity_joins
- transition_time
- can_show_ad_on_death
- globalsnode
- stats
- on_expire
- customdata
- expired
- playertype
- teamtype
- retain_actor
- add_actor_weak_ref
- session
- on_player_leave
- on_team_leave
- on_transition_out
- has_transitioned_in
- has_begun
- has_ended
- is_transitioning_out
- transition_out
- create_player
- create_team
- ba._dependency.DependencyComponent
- dep_is_present
- get_dynamic_deps
244class Egg(ba.Actor): 245 """A lovely egg that can be picked up for points.""" 246 247 def __init__(self, position: tuple[float, float, float] = (0.0, 1.0, 0.0)): 248 super().__init__() 249 activity = self.activity 250 assert isinstance(activity, EasterEggHuntGame) 251 shared = SharedObjects.get() 252 253 # Spawn just above the provided point. 254 self._spawn_pos = (position[0], position[1] + 1.0, position[2]) 255 ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[ 256 random.randrange(3) 257 ] 258 mats = [shared.object_material, activity.egg_material] 259 self.node = ba.newnode( 260 'prop', 261 delegate=self, 262 attrs={ 263 'model': activity.egg_model, 264 'color_texture': ctex, 265 'body': 'capsule', 266 'reflection': 'soft', 267 'model_scale': 0.5, 268 'body_scale': 0.6, 269 'density': 4.0, 270 'reflection_scale': [0.15], 271 'shadow_size': 0.6, 272 'position': self._spawn_pos, 273 'materials': mats, 274 }, 275 ) 276 277 def exists(self) -> bool: 278 return bool(self.node) 279 280 def handlemessage(self, msg: Any) -> Any: 281 if isinstance(msg, ba.DieMessage): 282 if self.node: 283 self.node.delete() 284 elif isinstance(msg, ba.HitMessage): 285 if self.node: 286 assert msg.force_direction is not None 287 self.node.handlemessage( 288 'impulse', 289 msg.pos[0], 290 msg.pos[1], 291 msg.pos[2], 292 msg.velocity[0], 293 msg.velocity[1], 294 msg.velocity[2], 295 1.0 * msg.magnitude, 296 1.0 * msg.velocity_magnitude, 297 msg.radius, 298 0, 299 msg.force_direction[0], 300 msg.force_direction[1], 301 msg.force_direction[2], 302 ) 303 else: 304 super().handlemessage(msg)
A lovely egg that can be picked up for points.
247 def __init__(self, position: tuple[float, float, float] = (0.0, 1.0, 0.0)): 248 super().__init__() 249 activity = self.activity 250 assert isinstance(activity, EasterEggHuntGame) 251 shared = SharedObjects.get() 252 253 # Spawn just above the provided point. 254 self._spawn_pos = (position[0], position[1] + 1.0, position[2]) 255 ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[ 256 random.randrange(3) 257 ] 258 mats = [shared.object_material, activity.egg_material] 259 self.node = ba.newnode( 260 'prop', 261 delegate=self, 262 attrs={ 263 'model': activity.egg_model, 264 'color_texture': ctex, 265 'body': 'capsule', 266 'reflection': 'soft', 267 'model_scale': 0.5, 268 'body_scale': 0.6, 269 'density': 4.0, 270 'reflection_scale': [0.15], 271 'shadow_size': 0.6, 272 'position': self._spawn_pos, 273 'materials': mats, 274 }, 275 )
Instantiates an Actor in the current ba.Activity.
Returns whether the Actor is still present in a meaningful way.
Note that a dying character should still return True here as long as their corpse is visible; this is about presence, not being 'alive' (see ba.Actor.is_alive() for that).
If this returns False, it is assumed the Actor can be completely deleted without affecting the game; this call is often used when pruning lists of Actors, such as with ba.Actor.autoretain()
The default implementation of this method always return True.
Note that the boolean operator for the Actor class calls this method, so a simple "if myactor" test will conveniently do the right thing even if myactor is set to None.
280 def handlemessage(self, msg: Any) -> Any: 281 if isinstance(msg, ba.DieMessage): 282 if self.node: 283 self.node.delete() 284 elif isinstance(msg, ba.HitMessage): 285 if self.node: 286 assert msg.force_direction is not None 287 self.node.handlemessage( 288 'impulse', 289 msg.pos[0], 290 msg.pos[1], 291 msg.pos[2], 292 msg.velocity[0], 293 msg.velocity[1], 294 msg.velocity[2], 295 1.0 * msg.magnitude, 296 1.0 * msg.velocity_magnitude, 297 msg.radius, 298 0, 299 msg.force_direction[0], 300 msg.force_direction[1], 301 msg.force_direction[2], 302 ) 303 else: 304 super().handlemessage(msg)
General message handling; can be passed any message object.
Inherited Members
- ba._actor.Actor
- autoretain
- on_expire
- expired
- is_alive
- activity
- getactivity