Skip to content

Commit 332ca75

Browse files
committed
I managed to break Gaia code reloading LOL
1 parent 4889934 commit 332ca75

File tree

8 files changed

+363
-218
lines changed

8 files changed

+363
-218
lines changed

Projects/Physics2D/Assets.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ module Assets =
1616
let SkyBoxFront = asset<Image> PackageName (nameof SkyBoxFront)
1717
let Capsule = asset<Image> PackageName (nameof Capsule)
1818
let Goo = asset<Image> PackageName (nameof Goo)
19-
let Link = asset<Image> PackageName (nameof Link)
19+
let Link = asset<Image> PackageName (nameof Link)
20+
let Car = asset<Image> PackageName (nameof Car)
21+
let Wheel = asset<Image> PackageName (nameof Wheel)
7.4 KB
Loading
1.98 KB
Loading
Lines changed: 166 additions & 185 deletions
Large diffs are not rendered by default.

Projects/Physics2D/Physics2D.fs

Lines changed: 189 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ open Nu
66

77
// this determines what state the game is in. To learn about ImSim in Nu, see -
88
// https://github.com/bryanedds/Nu/wiki/Immediate-Mode-for-Games-via-ImSim
9-
type GameState =
10-
| Enclosure
9+
type GameState = Enclosure = 0 | Racecourse = 1
1110

1211
// this extends the Game API to expose GameState as a property.
1312
[<AutoOpen>]
@@ -16,47 +15,210 @@ module Physics2DExtensions =
1615
member this.GetGameState world : GameState = this.Get (nameof Game.GameState) world
1716
member this.SetGameState (value : GameState) world = this.Set (nameof Game.GameState) value world
1817
member this.GameState = lens (nameof Game.GameState) this this.GetGameState this.SetGameState
19-
18+
member this.GetCarAcceleration world : float32 = this.Get (nameof Game.CarAcceleration) world
19+
member this.SetCarAcceleration (value : float32) world = this.Set (nameof Game.CarAcceleration) value world
20+
member this.CarAcceleration = lens (nameof Game.CarAcceleration) this this.GetCarAcceleration this.SetCarAcceleration
21+
2022
// this is the dispatcher that customizes the top-level behavior of our game.
2123
type Physics2DDispatcher () =
2224
inherit GameDispatcherImSim ()
2325

2426
// here we define default property values
2527
static member Properties =
26-
[define Game.GameState Enclosure]
27-
28-
// here we define game initialization
29-
override _.Register (_, world) =
30-
World.setEye2dCenter (v2 60f 0f) world
28+
[define Game.GameState GameState.Enclosure
29+
define Game.CarAcceleration 0f]
3130

3231
// here we define the game's top-level behavior
3332
override this.Process (game, world) =
3433

35-
// declare PlaygroundDispatcher screen
34+
// declare Enclosure screen
3635
let behavior = Dissolve (Constants.Dissolve.Default, None)
37-
let _ = World.beginScreen<EnclosureDispatcher> Simulants.Enclosure.Name (game.GetGameState world = Enclosure) behavior [] world
36+
let _ =
37+
World.beginScreen<DemoScreenDispatcher> (nameof GameState.Enclosure) (game.GetGameState world = GameState.Enclosure) behavior
38+
[Screen.CameraPositionDefault .= CameraAbsolute (v2 60f 0f)] world
3839
World.beginGroup Simulants.SceneGroup [] world
40+
41+
// define border
42+
let _ =
43+
World.doBlock2d Simulants.BorderEntity // A block uses static physics by default - it does not react to forces or collisions.
44+
[Entity.Size .= v3 500f 350f 0f
45+
Entity.BodyShape .= ContourShape // The body shape handles collisions and is independent of how it's displayed.
46+
{ Links = // A contour shape, unlike other shapes, is hollow.
47+
[|v3 -0.5f 0.5f 0f // Zero is the entity's center, one is the entity's size in positive direction.
48+
v3 0.5f 0.5f 0f
49+
v3 0.5f -0.5f 0f
50+
v3 -0.5f -0.5f 0f|]
51+
Closed = true // The last point connects to the first point.
52+
// There can be multiple shapes per body, TransformOpt and PropertiesOpt
53+
TransformOpt = None
54+
PropertiesOpt = None }
55+
// Continuous collision detection adds additional checks between frame positions
56+
// against high velocity objects tunneling through thin borders.
57+
Entity.CollisionDetection .= Continuous
58+
// Collision categories is a binary mask, defaulting to "1" (units place).
59+
// The border is set to be in a different category, "10" (twos place)
60+
// because we define fans later to not collide with the border.
61+
// Meanwhile, unless we change the collision mask (Entity.CollisionMask),
62+
// all entites default to collide with "*" (i.e. all collision categories).
63+
Entity.CollisionCategories .= "10"
64+
Entity.Elevation .= -1f // Draw order of the same elevation prioritizes entities with lower vertical position for 2D games.
65+
Entity.StaticImage .= Assets.Gameplay.SkyBoxFront] world
66+
67+
// define agent
68+
let (agentBody, _) =
69+
World.doCharacter2d "Agent"
70+
[Entity.Restitution .= 0.333f // bounciness
71+
Entity.GravityOverride .= None // characters have 3x gravity by default, get rid of it
72+
Entity.Friction .= 0.1f
73+
] world
74+
75+
// Keyboard controls for agent
76+
if world.ContextScreen.GetSelected world then
77+
let agentForce = 200f
78+
let agentTorque = 1f
79+
if World.isKeyboardKeyDown KeyboardKey.A world then
80+
World.applyBodyForce (v3 -1f 0f 0f * agentForce) None agentBody world
81+
if World.isKeyboardKeyDown KeyboardKey.D world then
82+
World.applyBodyForce (v3 1f 0f 0f * agentForce) None agentBody world
83+
if World.isKeyboardKeyDown KeyboardKey.W world then
84+
// Fly up despite gravity
85+
World.applyBodyForce (v3 0f 1f 0f * agentForce - World.getGravity2d world) None agentBody world
86+
if World.isKeyboardKeyDown KeyboardKey.S world then
87+
// Glide down despite gravity
88+
World.applyBodyForce (v3 0f -1f 0f * agentForce - World.getGravity2d world) None agentBody world
89+
if World.isKeyboardKeyDown KeyboardKey.Q world then
90+
World.applyBodyTorque (v3 1f 0f 0f * agentTorque) agentBody world
91+
if World.isKeyboardKeyDown KeyboardKey.E world then
92+
World.applyBodyTorque (v3 -1f 0f 0f * agentTorque) agentBody world
93+
3994
if World.doButton Simulants.BackEntity [] world && world.Unaccompanied then World.exit world
4095
World.endGroup world
4196
World.endScreen world
4297

43-
World.cam
44-
// Camera control
45-
if World.isKeyboardKeyDown KeyboardKey.Left world then
46-
World.setEye2dCenter (World.getEye2dCenter world - v2 1f 0f) world
47-
if World.isKeyboardKeyDown KeyboardKey.Right world then
48-
World.setEye2dCenter (World.getEye2dCenter world + v2 1f 0f) world
49-
if World.isKeyboardKeyDown KeyboardKey.Up world then
50-
World.setEye2dCenter (World.getEye2dCenter world + v2 0f 1f) world
51-
if World.isKeyboardKeyDown KeyboardKey.Down world then
52-
World.setEye2dCenter (World.getEye2dCenter world - v2 0f 1f) world
53-
if World.isKeyboardKeyDown KeyboardKey.PageUp world then
54-
World.setEye2dSize (World.getEye2dSize world * 1.01f) world
55-
if World.isKeyboardKeyDown KeyboardKey.PageDown world then
56-
World.setEye2dSize (World.getEye2dSize world * 0.99f) world
57-
if World.isKeyboardKeyDown KeyboardKey.Home world then
58-
World.setEye2dCenter (v2 60f 0f) world
59-
World.setEye2dSize Constants.Render.DisplayVirtualResolution.V2 world
98+
// declare Racecourse screen
99+
let behavior = Dissolve (Constants.Dissolve.Default, None)
100+
let _ =
101+
World.beginScreen<DemoScreenDispatcher> (nameof GameState.Racecourse) (game.GetGameState world = GameState.Racecourse) behavior
102+
[Screen.CameraPositionDefault .= CameraTracking (Relation.makeFromString "Car")] world
103+
World.beginGroup Simulants.SceneGroup [] world
104+
105+
// define racecourse
106+
let racecourse =
107+
[|v2 -20f 5f
108+
v2 -20f 0f
109+
v2 20f 0f
110+
v2 25f 0.25f
111+
v2 30f 1f
112+
v2 35f 4f
113+
v2 40f 0f
114+
v2 45f 0f
115+
v2 50f -1f
116+
v2 55f -2f
117+
v2 60f -2f
118+
v2 65f -1.25f
119+
v2 70f 0f
120+
v2 75f 0.3f
121+
v2 80f 1.5f
122+
v2 85f 3.5f
123+
v2 90f 0f
124+
v2 95f -0.5f
125+
v2 100f -1f
126+
v2 105f -2f
127+
v2 110f -2.5f
128+
v2 115f -1.3f
129+
v2 120f 0f
130+
v2 160f 0f
131+
v2 159f -10f
132+
v2 201f -10f
133+
v2 200f 0f
134+
v2 240f 0f
135+
v2 250f 5f
136+
v2 250f -10f
137+
v2 270f -10f
138+
v2 270f 0f
139+
v2 310f 0f
140+
v2 310f 5f|] |> Array.map (fun p -> p.V3 * Constants.Engine.Entity2dSizeDefault)
141+
let _ =
142+
World.doBlock2d "Racecourse"
143+
[Entity.Size .= v3 1f 1f 0f
144+
Entity.BodyShape .= ContourShape { Links = racecourse; Closed = false; TransformOpt = None; PropertiesOpt = None }]
145+
world
146+
for (p1, p2) in Array.pairwise racecourse do
147+
World.doStaticSprite $"Racecourse {p1} -> {p2}"
148+
[Entity.Position .= (p1 + p2) / 2f
149+
Entity.Size .= v3 ((p2 - p1).Magnitude / 2f) 2f 0f
150+
Entity.Rotation .= Quaternion.CreateLookAt2d (p2 - p1).V2
151+
Entity.StaticImage .= Assets.Default.Black] world
152+
153+
// define car
154+
let carMaxSpeed = 50f
155+
let carSpawnPosition = v3 0f 30f 0f
156+
let carPoints = [|
157+
v3 -2.5f -0.08f 0f
158+
v3 -2.375f 0.46f 0f
159+
v3 -0.58f 0.92f 0f
160+
v3 0.46f 0.92f 0f
161+
v3 2.5f 0.17f 0f
162+
v3 2.5f -0.205f 0f
163+
v3 2.3f -0.33f 0f
164+
v3 -2.25f -0.35f 0f|]
165+
let carBottomLeft = carPoints |> Array.reduce (fun a b -> v3 (min a.X b.X) (min a.Y b.Y) 0f)
166+
let carTopRight = carPoints |> Array.reduce (fun a b -> v3 (max a.X b.X) (max a.Y b.Y) 0f)
167+
let carSize = carTopRight - carBottomLeft
168+
let carGetRelativePosition p = (p - carBottomLeft) / carSize - v3Dup 0.5f
169+
let _ =
170+
World.doBox2d "Car"
171+
[Entity.BodyShape .= PointsShape {
172+
Points = Array.map carGetRelativePosition carPoints
173+
Profile = Convex
174+
TransformOpt = None
175+
PropertiesOpt = None }
176+
Entity.StaticImage .= Assets.Gameplay.Car
177+
Entity.Position .= carSpawnPosition
178+
Entity.Size .= carSize * Constants.Engine.Entity2dSizeDefault
179+
Entity.Substance .= Density 2f
180+
] world
181+
for (relation, position, density, frequency, friction, maxTorque, motorSpeed) in
182+
[("Back", v3 -1.709f 0.78f 0f, 0.8f, 5f, Some 0.9f, 20f,
183+
let acceleration = game.GetCarAcceleration world
184+
float32 (sign acceleration) * Math.SmoothStep(0f, carMaxSpeed, abs acceleration))
185+
("Front", v3 1.54f 0.8f 0f, 1f, 8.5f, None, 10f, 0f)] do
186+
let _ =
187+
World.doBall2d $"Wheel {relation}"
188+
[Entity.StaticImage .= Assets.Gameplay.Wheel
189+
Entity.Position .= carSpawnPosition + carGetRelativePosition position * Constants.Engine.Entity2dSizeDefault
190+
Entity.Size .= 0.5f * Constants.Engine.Entity2dSizeDefault
191+
Entity.Substance .= Density density
192+
match friction with Some f -> Entity.Friction .= f | _ -> ()
193+
] world
194+
let _ =
195+
World.doBodyJoint2d $"Wheel {relation} joint"
196+
[Entity.BodyJoint .= TwoBodyJoint2d {
197+
CreateTwoBodyJoint = fun _ _ car wheel ->
198+
nkast.Aether.Physics2D.Dynamics.Joints.WheelJoint (car, wheel, wheel.Position, new _(0f, 1.2f), true,
199+
Frequency = frequency, DampingRatio = 0.85f, MaxMotorTorque = maxTorque,
200+
MotorSpeed = motorSpeed, MotorEnabled = (abs motorSpeed >= carMaxSpeed * 0.06f)) }
201+
Entity.BodyJointTarget .= Relation.makeFromString "^/Car"
202+
Entity.BodyJointTarget2Opt .= Some (Relation.makeFromString $"^/Wheel {relation}")
203+
204+
] world
205+
()
206+
207+
// Keyboard controls for car
208+
let isAJustReleased =
209+
World.doSubscription "SubscribeARelease" Game.KeyboardKeyChangeEvent world
210+
|> Seq.exists (fun buttonChange -> buttonChange.KeyboardKey = KeyboardKey.A && not buttonChange.Down)
211+
if World.isKeyboardKeyDown KeyboardKey.A world then
212+
game.CarAcceleration.Map (fun a -> min (a + 2.0f * world.ClockTime) 1f) world
213+
elif World.isKeyboardKeyDown KeyboardKey.D world then
214+
game.CarAcceleration.Map (fun a -> max (a - 2.0f * world.ClockTime) -1f) world
215+
elif World.isKeyboardKeyPressed KeyboardKey.D world || isAJustReleased then
216+
game.SetCarAcceleration 0f world
217+
else game.CarAcceleration.Map (fun a -> a - float32 (sign a) * 2.0f * world.ClockTime) world
218+
219+
if World.doButton Simulants.BackEntity [] world && world.Unaccompanied then World.exit world
220+
World.endGroup world
221+
World.endScreen world
60222

61223
// handle Alt+F4 when not in editor
62224
if World.isKeyboardAltDown world &&

Projects/Physics2D/Physics2D.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
</Content>
4747
<Compile Include="Assets.fs" />
4848
<Compile Include="Simulants.fs" />
49-
<Compile Include="Enclosure.fs" />
49+
<Compile Include="DemoScreen.fs" />
5050
<Compile Include="Physics2D.fs" />
5151
<Compile Include="Physics2DPlugin.fs" />
5252
<Compile Include="Program.fs" />

Projects/Physics2D/Physics2DPlugin.fs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ type Physics2DPlugin () =
99

1010
// this exposes different editing modes in the editor
1111
override this.EditModes =
12-
Map.ofList
13-
[(nameof Enclosure, Game.SetGameState Enclosure)]
12+
Enum.GetValues<GameState> ()
13+
|> Array.map (fun v -> string v, Game.SetGameState v)
14+
|> Map.ofArray

Projects/Physics2D/Simulants.fs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,4 @@ module rec Simulants =
1010

1111
let [<Literal>] SceneGroup = "Scene"
1212
let [<Literal>] BackEntity = "Back"
13-
14-
let Enclosure = Game / nameof Enclosure
13+
let [<Literal>] BorderEntity = "Border"

0 commit comments

Comments
 (0)