I want to make a Mario 64-like game, but I do not understand how to reflect the keys.
Here is the source code I wrote.
```elm
-- MODEL
-- IDで役割を分ける。
type Id
= Key
| Player
| Floor
-- Msgには何がいるのか
type Msg
= AnimationFrame
| Resize (Quantity Float Pixels) (Quantity Float Pixels)
| KeyDown (Axis3d Meters WorldCoordinates)
| KeyUp
| Restart
init : () -> ( Model, Cmd Msg )
init _ =
({ world=initialWorld
, width=pixels 0
, height=pixels 0
, maybeRaycastResult = Nothing
, exposureValue = 0
}
, Task.perform
(\{ viewport } ->
Resize (pixels viewport.width) (pixels viewport.height)
)
Browser.Dom.getViewport
)
-- WORLD
initialWorld: World Data
initialWorld=
World.empty
|> World.withGravity (Acceleration.metersPerSecondSquared 9.80665)
Direction3d.negativeZ
|> World.add player
|> World.add floorBody
key:Body Data
key =
compound []
{ id = Key
, entity =
Scene3d.sphere (Material.matte Color.white)
(Sphere3d.atOrigin (millimeters 20))}
decodeKeyRay:
Camera3d Meters WorldCoordinates
-> Quantity Float Pixels
-> Quantity Float Pixels
-> (Axis3d Meters WorldCoordinates -> msg)
-> Decode.Decoder msg
decodeKeyRay camera3d width height rayToMsg =
Decode.map2
(\x y ->
rayToMsg
(Camera3d.ray
camera3d
(Rectangle2d.with
{ x1 = pixels 0
, y1 = height
, x2 = width
, y2 = pixels 0
}
)
(Point2d.pixels x y)
)
)
-- おそらくここにイベントリスナを書く
(Decode.field "leftKey" Decode.float)
(Decode.field "rightKey" Decode.float)
-- UPDATE
update : Msg -> Model -> Model
update msg model =
case msg of
AnimationFrame ->
{ model | world = World.simulate (seconds (1 / 60)) model.world }
Resize width height ->
{ model | width = width, height = height }
-- 書き直し箇所その2 ここをelm-physicsのLack.elのupdate関数を参考に書き換える
KeyDown keyRay ->
case model.maybeRaycastResult of
Just raycastResult ->
let
worldPoint =
Point3d.placeIn
(Body.frame raycastResult.body)
raycastResult.point
plane =
Plane3d.through
worldPoint
(Viewpoint3d.viewDirection (Camera3d.viewpoint camera))
in
{ model
| world =
World.update
(\body ->
if (Body.data body).id == Key then
case Axis3d.intersectionWithPlane plane keyRay of
Just intersection ->
Body.moveTo intersection body
Nothing ->
body
else
body
)
model.world
}
Nothing ->
model
KeyUp ->
{ model
| maybeRaycastResult = Nothing
, world =
World.keepIf
(\body -> (Body.data body).id /= Key)
model.world
}
Restart ->
{ model | world=initialWorld }
-- SUBSCRIPTISONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.batch
[ Browser.Events.onResize
(\width height ->
Resize (pixels (toFloat width)) (pixels (toFloat height))
)
, Browser.Events.onAnimationFrame (\_ -> AnimationFrame)
]
-- VIEW
view : Model -> Html Msg
view model =
let
entities =
List.map
(\body ->
Scene3d.placeIn
(frame body)
(data body).entity
)
(World.bodies model.world)
in
Html.div [ ]
[ Scene3d.sunny
{ upDirection = Direction3d.z
, sunlightDirection = Direction3d.xyZ (Angle.degrees 135) (Angle.degrees -60)
, shadows = True
, camera = camera
, dimensions =
( Pixels.int (round (Pixels.toFloat model.width))
, Pixels.int (round (Pixels.toFloat model.height))
)
, background = Scene3d.transparentBackground
, clipDepth = Length.meters 0.1
, entities = entities
}
]
-- RENDERING
camera : Camera3d Meters WorldCoordinates
camera =
-- 俯瞰する類のカメラかな?
-- the model
Camera3d.perspective
{ viewpoint =
Viewpoint3d.lookAt
{ eyePoint = Point3d.meters 3 4 2
, focalPoint = Point3d.meters -0.5 -0.5 0
, upDirection = Direction3d.positiveZ
}
, verticalFieldOfView = Angle.degrees 30
}
```
Is there any good solution?