Skip to content

Commit ef73a84

Browse files
committed
Correctly use non-default last_ball_state
1 parent 8124037 commit ef73a84

File tree

5 files changed

+90
-13
lines changed

5 files changed

+90
-13
lines changed

crates/bevyhavior_simulator/src/bin/corner_kicks.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
use bevy::prelude::*;
22

3+
use linear_algebra::{point, vector};
34
use scenario::scenario;
45
use spl_network_messages::{GameState, PlayerNumber, SubState, Team};
56

67
use bevyhavior_simulator::{
8+
ball::BallResource,
79
game_controller::{GameController, GameControllerCommand},
810
robot::Robot,
911
time::{Ticks, TicksTime},
1012
};
13+
use types::ball_position::SimulatorBallState;
1114

1215
#[scenario]
1316
fn corner_kicks(app: &mut App) {
@@ -38,13 +41,22 @@ fn update(
3841
mut game_controller_commands: EventWriter<GameControllerCommand>,
3942
time: Res<Time<Ticks>>,
4043
mut exit: EventWriter<AppExit>,
44+
mut ball: ResMut<BallResource>,
4145
) {
4246
if time.ticks() == 3000 {
4347
game_controller_commands.send(GameControllerCommand::SetSubState(
4448
Some(SubState::CornerKick),
4549
Team::Hulks,
4650
));
4751
}
52+
53+
if time.ticks() == 4500 {
54+
ball.state = Some(SimulatorBallState {
55+
position: point!(-2.25, 1.0),
56+
velocity: vector![-6.0, 2.0],
57+
});
58+
}
59+
4860
if time.ticks() == 5000 {
4961
game_controller_commands.send(GameControllerCommand::SetSubState(
5062
Some(SubState::CornerKick),

crates/control/src/kicking_team_filter.rs

+65-12
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,37 @@
1+
use std::time::{Duration, SystemTime};
2+
13
use color_eyre::Result;
24
use serde::{Deserialize, Serialize};
35

46
use context_attribute::context;
5-
use framework::MainOutput;
7+
use framework::{AdditionalOutput, MainOutput};
68
use spl_network_messages::{SubState, Team};
79
use types::{
810
filtered_whistle::FilteredWhistle, game_controller_state::GameControllerState,
911
world_state::BallState,
1012
};
1113

1214
#[derive(Deserialize, Serialize)]
13-
pub struct KickingTeamFilter {}
15+
pub struct KickingTeamFilter {
16+
time_last_ball_state_became_default: SystemTime,
17+
last_ball_state: BallState,
18+
last_non_default_ball_state: Option<BallState>,
19+
}
1420

1521
#[context]
1622
pub struct CreationContext {}
1723

1824
#[context]
1925
pub struct CycleContext {
20-
last_ball_state: CyclerState<BallState, "last_ball_position">,
26+
last_ball_state: CyclerState<BallState, "last_ball_state">,
2127
game_controller_state: RequiredInput<Option<GameControllerState>, "game_controller_state?">,
2228
detected_free_kick_kicking_team: Input<Option<Team>, "detected_free_kick_kicking_team?">,
2329
filtered_whistle: Input<FilteredWhistle, "filtered_whistle">,
30+
31+
duration_to_keep_non_default_last_ball_state:
32+
Parameter<Duration, "kicking_team_filter.duration_to_keep_non_default_last_ball_state">,
33+
34+
additonal_last_ball_state: AdditionalOutput<BallState, "last_ball_state">,
2435
}
2536

2637
#[context]
@@ -30,50 +41,92 @@ pub struct MainOutputs {
3041

3142
impl KickingTeamFilter {
3243
pub fn new(_context: CreationContext) -> Result<Self> {
33-
Ok(KickingTeamFilter {})
44+
Ok(KickingTeamFilter {
45+
time_last_ball_state_became_default: SystemTime::now(),
46+
last_ball_state: Default::default(),
47+
last_non_default_ball_state: Default::default(),
48+
})
3449
}
3550

36-
pub fn cycle(&mut self, context: CycleContext) -> Result<MainOutputs> {
51+
pub fn cycle(&mut self, mut context: CycleContext) -> Result<MainOutputs> {
52+
context
53+
.additonal_last_ball_state
54+
.fill_if_subscribed(|| *context.last_ball_state);
55+
3756
let game_controller_state = context.game_controller_state;
3857
let sub_state = context.game_controller_state.sub_state;
39-
let last_ball_state = context.last_ball_state;
58+
59+
let duration_since_last_non_default_ball_state =
60+
SystemTime::now().duration_since(self.time_last_ball_state_became_default)?;
61+
62+
if *context.last_ball_state == BallState::default()
63+
&& self.last_ball_state != BallState::default()
64+
{
65+
self.time_last_ball_state_became_default = SystemTime::now();
66+
}
67+
self.last_ball_state = *context.last_ball_state;
68+
69+
if *context.last_ball_state != BallState::default()
70+
|| *context.last_ball_state == BallState::default()
71+
&& duration_since_last_non_default_ball_state
72+
>= *context.duration_to_keep_non_default_last_ball_state
73+
{
74+
self.last_non_default_ball_state = Some(*context.last_ball_state);
75+
}
4076

4177
let filtered_kicking_team = if game_controller_state.kicking_team.is_some() {
4278
game_controller_state.kicking_team
4379
} else if context.detected_free_kick_kicking_team.is_some() {
4480
context.detected_free_kick_kicking_team.copied()
45-
} else {
81+
} else if let Some(last_non_default_ball_state) = self.last_non_default_ball_state {
4682
match sub_state {
4783
Some(SubState::CornerKick)
48-
if last_ball_state.ball_in_field.x().is_sign_positive() =>
84+
if last_non_default_ball_state
85+
.ball_in_field
86+
.x()
87+
.is_sign_positive() =>
4988
{
5089
Some(Team::Hulks)
5190
}
5291
Some(SubState::CornerKick)
53-
if last_ball_state.ball_in_field.x().is_sign_negative() =>
92+
if last_non_default_ball_state
93+
.ball_in_field
94+
.x()
95+
.is_sign_negative() =>
5496
{
5597
Some(Team::Opponent)
5698
}
5799
Some(SubState::GoalKick)
58-
if last_ball_state.ball_in_field.x().is_sign_positive() =>
100+
if last_non_default_ball_state
101+
.ball_in_field
102+
.x()
103+
.is_sign_positive() =>
59104
{
60105
Some(Team::Opponent)
61106
}
62107
Some(SubState::GoalKick)
63-
if last_ball_state.ball_in_field.x().is_sign_negative() =>
108+
if last_non_default_ball_state
109+
.ball_in_field
110+
.x()
111+
.is_sign_negative() =>
64112
{
65113
Some(Team::Hulks)
66114
}
67115
None => match (
68116
context.filtered_whistle.is_detected,
69-
last_ball_state.ball_in_field.x().is_sign_positive(),
117+
last_non_default_ball_state
118+
.ball_in_field
119+
.x()
120+
.is_sign_positive(),
70121
) {
71122
(true, true) => Some(Team::Opponent),
72123
(true, false) => Some(Team::Hulks),
73124
_ => None,
74125
},
75126
_ => None,
76127
}
128+
} else {
129+
None
77130
};
78131
Ok(MainOutputs {
79132
filtered_kicking_team: filtered_kicking_team.into(),

crates/types/src/penalty_shot_direction.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
1111
PathSerialize,
1212
PathDeserialize,
1313
PathIntrospect,
14+
PartialEq,
1415
)]
1516
pub enum PenaltyShotDirection {
1617
#[default]

crates/types/src/world_state.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@ pub struct WorldState {
3232
}
3333

3434
#[derive(
35-
Clone, Copy, Debug, Serialize, Deserialize, PathSerialize, PathDeserialize, PathIntrospect,
35+
Clone,
36+
Copy,
37+
Debug,
38+
Serialize,
39+
Deserialize,
40+
PathSerialize,
41+
PathDeserialize,
42+
PathIntrospect,
43+
PartialEq,
3644
)]
3745
pub struct BallState {
3846
pub ball_in_ground: Point2<Ground>,

etc/parameters/default.json

+3
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,9 @@
641641
}
642642
]
643643
},
644+
"kicking_team_filter": {
645+
"duration_to_keep_non_default_last_ball_state": { "nanos": 3000000000, "secs": 3 }
646+
},
644647
"localization": {
645648
"circle_measurement_noise": [1000.0, 1000.0],
646649
"gradient_convergence_threshold": 1e-2,

0 commit comments

Comments
 (0)