@@ -15,6 +15,15 @@ import {
1515} from "@/util/TypeConversions"
1616import { deltaFieldTransformsPhysicalProp } from "@/util/threejs/MeshCreation"
1717import { MiraType } from "./MirabufLoader"
18+ import MatchMode , { MatchModeType } from "@/systems/match_mode/MatchMode"
19+
20+ export enum ContactType {
21+ ROBOT_ENTERS = "Opponent Robot Enters" ,
22+ ANY_ROBOT_INSIDE = "Collision with Any Robot Inside" ,
23+ BOTH_ROBOTS_INSIDE = "Collision with Both Robots Inside" ,
24+ RED_ROBOT_INSIDE = "Collision with Red Robot Inside" ,
25+ BLUE_ROBOT_INSIDE = "Collision with Blue Robot Inside" ,
26+ }
1827import MirabufSceneObject , { RigidNodeAssociate } from "./MirabufSceneObject"
1928
2029class ProtectedZoneSceneObject extends SceneObject {
@@ -30,7 +39,7 @@ class ProtectedZoneSceneObject extends SceneObject {
3039 shininess : 0.0 ,
3140 opacity : 0.8 ,
3241 transparent : true ,
33- } ) //0x0000ff
42+ } )
3443 static transparentMaterial = new THREE . MeshPhongMaterial ( {
3544 color : 0x0000 ,
3645 shininess : 0.0 ,
@@ -46,14 +55,27 @@ class ProtectedZoneSceneObject extends SceneObject {
4655 private _prefs ?: ProtectedZonePreferences
4756 private _joltBodyId ?: Jolt . BodyID
4857 private _mesh ?: THREE . Mesh
49- private _collision ?: ( event : OnContactAddedEvent ) => void
50- private _collisionPersisted ?: ( event : OnContactPersistedEvent ) => void
58+ private _collision ?: ( event : OnContactAddedEvent | OnContactPersistedEvent ) => void
5159 private _collisionRemoved ?: ( event : OnContactRemovedEvent ) => void
5260
5361 private _robotsInside : Map < MirabufSceneObject , number > = new Map ( )
5462
5563 private _lastRobotCollisionTime : number = 0
5664
65+ private isZoneActive ( ) : boolean {
66+ if ( ! this . _prefs ?. activeDuring ) {
67+ return [ MatchModeType . AUTONOMOUS , MatchModeType . TELEOP , MatchModeType . ENDGAME ] . includes (
68+ MatchMode . getInstance ( ) . getMatchModeType ( )
69+ )
70+ }
71+ return this . _prefs . activeDuring . includes ( MatchMode . getInstance ( ) . getMatchModeType ( ) )
72+ }
73+
74+ private isRobotInside ( robot : MirabufSceneObject ) : boolean {
75+ const timeInside = this . _robotsInside . get ( robot ) ?? 0
76+ return Date . now ( ) - timeInside < 100
77+ }
78+
5779 public constructor ( parentAssembly : MirabufSceneObject , index : number , render ?: boolean ) {
5880 super ( )
5981
@@ -104,8 +126,8 @@ class ProtectedZoneSceneObject extends SceneObject {
104126 this . _mesh ?. scale . set ( props . scale . x , props . scale . y , props . scale . z )
105127 }
106128
107- // Detect when something enters the zone
108- this . _collision = ( event : OnContactAddedEvent ) => {
129+ // Detect when something enters or persists in the zone
130+ this . _collision = ( event : OnContactAddedEvent | OnContactPersistedEvent ) => {
109131 const body1 = event . message . body1
110132 const body2 = event . message . body2
111133
@@ -115,55 +137,12 @@ class ProtectedZoneSceneObject extends SceneObject {
115137 this . zoneCollision ( body1 )
116138 }
117139
118- // If the preference is set to require robot contact, we want to penalize robots here
119- if ( ! this . _prefs ?. requireRobotContact ) return
120- const [ collisionObjectBody1 , collisionObjectBody2 ] = [ body1 , body2 ] . map ( body => {
121- const associate = World . physicsSystem . getBodyAssociation ( body ) as RigidNodeAssociate | undefined
122- return associate ?. sceneObject as MirabufSceneObject | undefined
123- } )
124- if ( ! collisionObjectBody1 || ! collisionObjectBody2 ) return
125- // Makes sure that both robots are from opposing alliances
126- if ( collisionObjectBody1 . alliance === collisionObjectBody2 . alliance ) return
127- // Ensure that both bodies are robots are inside the zone
128- if (
129- Date . now ( ) - ( this . _robotsInside . get ( collisionObjectBody1 ) ?? 0 ) > 500 ||
130- Date . now ( ) - ( this . _robotsInside . get ( collisionObjectBody2 ) ?? 0 ) > 500
131- ) {
132- return
133- }
134- // Ensures that infinite collisions do not occur
135- if ( Date . now ( ) - this . _lastRobotCollisionTime < 1000 ) return
136- this . _lastRobotCollisionTime = Date . now ( )
137-
138- // Penalize the robot that entered the opposing alliance protected zone
139- if ( collisionObjectBody1 . alliance === this . _prefs ?. alliance ) {
140- SimulationSystem . robotPenalty (
141- collisionObjectBody2 ,
142- this . _prefs ?. penaltyPoints ?? 0 ,
143- `Touched robot in protected zone`
144- )
145- } else {
146- SimulationSystem . robotPenalty (
147- collisionObjectBody1 ,
148- this . _prefs ?. penaltyPoints ?? 0 ,
149- `Touched robot in protected zone`
150- )
151- }
140+ // Handle contact-based penalties based on the configured contact type
141+ if ( this . _prefs ?. contactType == ContactType . ROBOT_ENTERS || ! this . isZoneActive ( ) ) return
142+ this . handleContactPenalty ( body1 , body2 )
152143 }
153144 OnContactAddedEvent . addListener ( this . _collision )
154-
155- // Detects when something persists in the zone
156- this . _collisionPersisted = ( event : OnContactPersistedEvent ) => {
157- const body1 = event . message . body1
158- const body2 = event . message . body2
159-
160- if ( body1 . GetIndexAndSequenceNumber ( ) == this . _joltBodyId ?. GetIndexAndSequenceNumber ( ) ) {
161- this . zoneCollision ( body2 )
162- } else if ( body2 . GetIndexAndSequenceNumber ( ) == this . _joltBodyId ?. GetIndexAndSequenceNumber ( ) ) {
163- this . zoneCollision ( body1 )
164- }
165- }
166- OnContactPersistedEvent . addListener ( this . _collisionPersisted )
145+ OnContactPersistedEvent . addListener ( this . _collision )
167146
168147 // Detects when something leaves the zone
169148 this . _collisionRemoved = ( event : OnContactRemovedEvent ) => {
@@ -224,31 +203,102 @@ class ProtectedZoneSceneObject extends SceneObject {
224203 }
225204 }
226205
227- if ( this . _collision ) OnContactAddedEvent . removeListener ( this . _collision )
206+ if ( this . _collision ) {
207+ OnContactAddedEvent . removeListener ( this . _collision )
208+ OnContactPersistedEvent . removeListener ( this . _collision )
209+ }
228210 if ( this . _collisionRemoved ) OnContactRemovedEvent . removeListener ( this . _collisionRemoved )
229211 }
230212
231213 private zoneCollision ( collisionID : Jolt . BodyID ) {
214+ if ( ! this . isZoneActive ( ) ) return
215+
232216 const associate = < RigidNodeAssociate > World . physicsSystem . getBodyAssociation ( collisionID )
233217 const collisionObject = associate . sceneObject as MirabufSceneObject
234- if ( collisionObject . miraType === MiraType . ROBOT && collisionObject . alliance !== this . _prefs ?. alliance ) {
235- const timeInside = this . _robotsInside . get ( collisionObject ) ?? 0
236- if ( ! this . _prefs ?. requireRobotContact && Date . now ( ) - timeInside > 500 ) {
237- SimulationSystem . robotPenalty (
238- collisionObject ,
239- this . _prefs ?. penaltyPoints ?? 0 ,
240- `Entered protected zone`
241- )
242- }
243- this . _robotsInside . set ( collisionObject , Date . now ( ) )
218+ if ( collisionObject . miraType !== MiraType . ROBOT ) return
219+
220+ if (
221+ this . _prefs ?. contactType === ContactType . ROBOT_ENTERS &&
222+ collisionObject . alliance !== this . _prefs ?. alliance &&
223+ ! this . isRobotInside ( collisionObject )
224+ ) {
225+ SimulationSystem . robotPenalty ( collisionObject , this . _prefs ?. penaltyPoints ?? 0 , `Entered protected zone` )
244226 }
227+
228+ this . _robotsInside . set ( collisionObject , Date . now ( ) )
245229 }
246230
247231 private zoneCollisionRemoved ( collisionID : Jolt . BodyID ) {
248232 const associate = < RigidNodeAssociate > World . physicsSystem . getBodyAssociation ( collisionID )
249233 const collisionObject = associate . sceneObject as MirabufSceneObject
250234 this . _robotsInside . set ( collisionObject , Date . now ( ) )
251235 }
236+
237+ private handleContactPenalty ( body1 : Jolt . BodyID , body2 : Jolt . BodyID ) {
238+ const [ collisionObjectBody1 , collisionObjectBody2 ] = [ body1 , body2 ] . map ( body => {
239+ const associate = World . physicsSystem . getBodyAssociation ( body ) as RigidNodeAssociate | undefined
240+ return associate ?. sceneObject as MirabufSceneObject | undefined
241+ } )
242+
243+ if ( ! collisionObjectBody1 || ! collisionObjectBody2 ) return
244+ if ( collisionObjectBody1 . miraType !== MiraType . ROBOT || collisionObjectBody2 . miraType !== MiraType . ROBOT ) return
245+
246+ // Only penalize collisions between robots from different alliances
247+ if ( collisionObjectBody1 . alliance === collisionObjectBody2 . alliance ) return
248+
249+ // Ensures that infinite collisions do not occur
250+ if ( Date . now ( ) - this . _lastRobotCollisionTime < 500 ) return
251+
252+ let shouldPenalize = false
253+
254+ // Find the robot that has the opposite alliance from the zone
255+ const opposingRobot = [ collisionObjectBody1 , collisionObjectBody2 ] . find (
256+ robot => robot . alliance !== this . _prefs ?. alliance
257+ )
258+ if ( ! opposingRobot ) return
259+ switch ( this . _prefs ?. contactType ) {
260+ case ContactType . BOTH_ROBOTS_INSIDE :
261+ // Penalize opposing robot if both robots are inside the zone and colliding
262+ if ( this . isRobotInside ( collisionObjectBody1 ) && this . isRobotInside ( collisionObjectBody2 ) ) {
263+ shouldPenalize = true
264+ }
265+ break
266+
267+ case ContactType . ANY_ROBOT_INSIDE :
268+ // Penalize if any robot is inside the zone when collision occurs
269+ if ( this . isRobotInside ( collisionObjectBody1 ) || this . isRobotInside ( collisionObjectBody2 ) ) {
270+ shouldPenalize = true
271+ }
272+ break
273+
274+ case ContactType . RED_ROBOT_INSIDE : {
275+ // Penalize if the red robot is inside the zone when collision occurs
276+ const redRobot = [ collisionObjectBody1 , collisionObjectBody2 ] . find ( robot => robot . alliance === "red" )
277+ if ( redRobot && this . isRobotInside ( redRobot ) ) {
278+ shouldPenalize = true
279+ }
280+ break
281+ }
282+
283+ case ContactType . BLUE_ROBOT_INSIDE : {
284+ // Penalize if the blue robot is inside the zone when collision occurs
285+ const blueRobot = [ collisionObjectBody1 , collisionObjectBody2 ] . find ( robot => robot . alliance === "blue" )
286+ if ( blueRobot && this . isRobotInside ( blueRobot ) ) {
287+ shouldPenalize = true
288+ }
289+ break
290+ }
291+ }
292+
293+ if ( shouldPenalize ) {
294+ this . _lastRobotCollisionTime = Date . now ( )
295+ SimulationSystem . robotPenalty (
296+ opposingRobot ,
297+ this . _prefs ?. penaltyPoints ?? 0 ,
298+ `Contact penalty in protected zone`
299+ )
300+ }
301+ }
252302}
253303
254304export default ProtectedZoneSceneObject
0 commit comments