@@ -3,6 +3,7 @@ package controller
3
3
import (
4
4
"github.com/RoboCup-SSL/ssl-game-controller/pkg/refproto"
5
5
"log"
6
+ "math"
6
7
)
7
8
8
9
// BallPlacementPos determines the ball placement position based on the game event
@@ -17,81 +18,134 @@ func (e *Engine) BallPlacementPos() *Location {
17
18
18
19
switch event .Type {
19
20
case GameEventBallLeftFieldTouchLine :
20
- return validateProtoLocation (event .Details .BallLeftFieldTouchLine .Location )
21
+ return e . validateProtoLocation (event .Details .BallLeftFieldTouchLine .Location )
21
22
case GameEventBallLeftFieldGoalLine :
22
- // TODO corner
23
- return validateProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
23
+ if event .Details .BallLeftFieldGoalLine .Location != nil && e .isGoalKick (event ) {
24
+ location := mapProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
25
+ maxX := e .Geometry .FieldLength / 2 - e .Geometry .PlacementOffsetGoalLineGoalKick
26
+ if math .Abs (location .X ) > maxX {
27
+ location .X = math .Copysign (maxX , location .X )
28
+ }
29
+ return e .validateLocation (location )
30
+ }
31
+ return e .validateProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
24
32
case GameEventIcing :
25
- return validateProtoLocation (event .Details .Icing .KickLocation )
33
+ return e . validateProtoLocation (event .Details .Icing .KickLocation )
26
34
case GameEventGoal :
27
35
return & Location {X : 0.0 , Y : 0.0 }
28
36
case GameEventIndirectGoal :
29
- return validateProtoLocation (event .Details .IndirectGoal .KickLocation )
37
+ return e . validateProtoLocation (event .Details .IndirectGoal .KickLocation )
30
38
case GameEventChippedGoal :
31
- return validateProtoLocation (event .Details .ChippedGoal .KickLocation )
39
+ return e . validateProtoLocation (event .Details .ChippedGoal .KickLocation )
32
40
case GameEventBotTippedOver :
33
- return validateProtoLocation (event .Details .BotTippedOver .Location )
41
+ return e . validateProtoLocation (event .Details .BotTippedOver .Location )
34
42
case GameEventBotInterferedPlacement :
35
- return validateLocation (e .State .PlacementPos )
43
+ return e . validateLocation (e .State .PlacementPos )
36
44
case GameEventBotCrashDrawn :
37
- return validateProtoLocation (event .Details .BotCrashDrawn .Location )
45
+ return e . validateProtoLocation (event .Details .BotCrashDrawn .Location )
38
46
case GameEventBotKickedBallTooFast :
39
- return validateProtoLocation (event .Details .BotKickedBallTooFast .Location )
47
+ return e . validateProtoLocation (event .Details .BotKickedBallTooFast .Location )
40
48
case GameEventBotDribbledBallTooFar :
41
- return validateProtoLocation (event .Details .BotDribbledBallTooFar .Start )
49
+ return e . validateProtoLocation (event .Details .BotDribbledBallTooFar .Start )
42
50
case GameEventBotCrashUnique :
43
- return validateProtoLocation (event .Details .BotCrashUnique .Location )
51
+ return e . validateProtoLocation (event .Details .BotCrashUnique .Location )
44
52
case GameEventBotCrashUniqueContinue :
45
- return validateProtoLocation (event .Details .BotCrashUniqueContinue .Location )
53
+ return e . validateProtoLocation (event .Details .BotCrashUniqueContinue .Location )
46
54
case GameEventBotPushedBot :
47
- return validateProtoLocation (event .Details .BotPushedBot .Location )
55
+ return e . validateProtoLocation (event .Details .BotPushedBot .Location )
48
56
case GameEventBotPushedBotContinue :
49
- return validateProtoLocation (event .Details .BotPushedBotContinue .Location )
57
+ return e . validateProtoLocation (event .Details .BotPushedBotContinue .Location )
50
58
case GameEventBotHeldBallDeliberately :
51
- return validateProtoLocation (event .Details .BotHeldBallDeliberately .Location )
59
+ return e . validateProtoLocation (event .Details .BotHeldBallDeliberately .Location )
52
60
case GameEventAttackerDoubleTouchedBall :
53
- return validateProtoLocation (event .Details .AttackerDoubleTouchedBall .Location )
61
+ return e . validateProtoLocation (event .Details .AttackerDoubleTouchedBall .Location )
54
62
case GameEventAttackerTooCloseToDefenseArea :
55
- return validateProtoLocation (event .Details .AttackerTooCloseToDefenseArea .Location )
63
+ return e . validateProtoLocation (event .Details .AttackerTooCloseToDefenseArea .Location )
56
64
case GameEventAttackerInDefenseArea :
57
- return validateProtoLocation (event .Details .AttackerInDefenseArea .Location )
65
+ return e . validateProtoLocation (event .Details .AttackerInDefenseArea .Location )
58
66
case GameEventAttackerTouchedKeeper :
59
- return validateProtoLocation (event .Details .AttackerTouchedKeeper .Location )
67
+ return e . validateProtoLocation (event .Details .AttackerTouchedKeeper .Location )
60
68
case GameEventDefenderTooCloseToKickPoint :
61
- return validateLocation (e .State .PlacementPos )
69
+ return e . validateLocation (e .State .PlacementPos )
62
70
case GameEventDefenderInDefenseAreaPartially :
63
- return validateProtoLocation (event .Details .DefenderInDefenseAreaPartially .Location )
71
+ return e . validateProtoLocation (event .Details .DefenderInDefenseAreaPartially .Location )
64
72
case GameEventDefenderInDefenseArea :
65
- // TODO penalty mark
66
- return nil
73
+ teamInFavor := event .ByTeam ().Opposite ()
74
+ location := Location {}
75
+ location .X = (e .Geometry .FieldLength / 2.0 ) - e .Geometry .PenaltyAreaDepth
76
+ if e .State .TeamState [teamInFavor ].OnPositiveHalf {
77
+ location .X *= - 1
78
+ }
79
+ return & location
67
80
case GameEventKeeperHeldBall :
68
- return validateProtoLocation (event .Details .KeeperHeldBall .Location )
81
+ return e . validateProtoLocation (event .Details .KeeperHeldBall .Location )
69
82
case GameEventKickTimeout :
70
- return validateLocation (e .State .PlacementPos )
83
+ return e . validateLocation (e .State .PlacementPos )
71
84
case GameEventNoProgressInGame :
72
- return validateProtoLocation (event .Details .NoProgressInGame .Location )
85
+ return e . validateProtoLocation (event .Details .NoProgressInGame .Location )
73
86
case GameEventPlacementFailedByTeamInFavor :
74
- return validateLocation (e .State .PlacementPos )
87
+ return e . validateLocation (e .State .PlacementPos )
75
88
case GameEventPlacementFailedByOpponent :
76
- return validateLocation (e .State .PlacementPos )
89
+ return e . validateLocation (e .State .PlacementPos )
77
90
default :
78
91
log .Print ("Warn: Unknown game event: " , event .Type )
79
92
return nil
80
93
}
81
94
}
82
95
83
- func validateProtoLocation (location * refproto.Location ) * Location {
96
+ func (e * Engine ) isGoalKick (event * GameEvent ) bool {
97
+ teamInFavor := event .ByTeam ().Opposite ()
98
+ location := mapProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
99
+ if e .State .TeamState [teamInFavor ].OnPositiveHalf && location .X > 0 {
100
+ return true
101
+ }
102
+ if ! e .State .TeamState [teamInFavor ].OnPositiveHalf && location .X < 0 {
103
+ return true
104
+ }
105
+ return false
106
+ }
107
+
108
+ func mapProtoLocation (location * refproto.Location ) * Location {
109
+ return & Location {X : float64 (* location .X ), Y : float64 (* location .Y )}
110
+ }
111
+
112
+ func (e * Engine ) validateProtoLocation (location * refproto.Location ) * Location {
84
113
if location == nil {
85
114
return nil
86
115
}
87
- return validateLocation (& Location { X : * location . X , Y : * location . Y } )
116
+ return e . validateLocation (mapProtoLocation ( location ) )
88
117
}
89
118
90
- func validateLocation (location * Location ) * Location {
119
+ func ( e * Engine ) validateLocation (location * Location ) * Location {
91
120
if location == nil {
92
121
return nil
93
122
}
94
- // TODO move inside field
95
- // TODO move away from defense area
123
+
124
+ e .movePositionInsideField (location )
125
+ e .movePositionOutOfDefenseArea (location )
126
+
96
127
return location
97
128
}
129
+
130
+ func (e * Engine ) movePositionOutOfDefenseArea (location * Location ) {
131
+ maxX := e .Geometry .FieldLength / 2 - e .Geometry .PenaltyAreaDepth - e .Geometry .PlacementOffsetDefenseArea
132
+ minY := e .Geometry .PenaltyAreaWidth + e .Geometry .PlacementOffsetDefenseArea
133
+ if math .Abs (location .X ) > maxX && math .Abs (location .Y ) < minY {
134
+ if math .Abs (maxX - math .Abs (location .X )) < math .Abs (minY - math .Abs (location .Y )) {
135
+ location .X = math .Copysign (maxX , location .X )
136
+ } else {
137
+ location .Y = math .Copysign (minY , location .Y )
138
+ }
139
+ }
140
+ }
141
+
142
+ func (e * Engine ) movePositionInsideField (location * Location ) {
143
+ maxX := e .Geometry .FieldLength / 2 - e .Geometry .PlacementOffsetGoalLine
144
+ if math .Abs (location .X ) > maxX {
145
+ location .X = math .Copysign (maxX , location .X )
146
+ }
147
+ maxY := e .Geometry .FieldWidth / 2 - e .Geometry .PlacementOffsetTouchLine
148
+ if math .Abs (location .Y ) > maxY {
149
+ location .Y = math .Copysign (maxY , location .Y )
150
+ }
151
+ }
0 commit comments