Skip to content

Commit

Permalink
Using a formula to calculate the trajectory
Browse files Browse the repository at this point in the history
  • Loading branch information
Patitotective committed Jun 1, 2024
1 parent 7f68ab2 commit 13abc80
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 77 deletions.
11 changes: 9 additions & 2 deletions src/frontend/simulations/matter.nim
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ proc createRender*(options: JsObject): JsObject {.importjs: "Matter.Render.creat
proc jsVector*(x, y: SomeNumber): JsVector = JsVector JsObject{x: x, y: y}
proc jsVector*(x, y: JsObject): JsVector = JsVector JsObject{x: x, y: y}

proc `x`*(v: JsVector): float64 =
JsObject(v).x.to(float64)

proc `y`*(v: JsVector): float64 =
JsObject(v).y.to(float64)

proc toTuple*(v: JsVector): tuple[x, y: float64] =
(x: v.x, y: v.y)

proc `*`*(v1, v2: JsVector): JsVector =
JsVector JsObject{x: JsObject(v1).x * JsObject(v2).x, y: JsObject(v1).y * JsObject(v2).y}

Expand All @@ -53,5 +62,3 @@ proc `-`*(v1: JsVector, v2: float64): JsVector =

proc `/`*(v1: JsVector, v2: float64): JsVector =
JsVector JsObject{x: JsObject(v1).x / v2.toJs, y: JsObject(v1).y / v2.toJs}


172 changes: 97 additions & 75 deletions src/frontend/simulations/parabola.nim
Original file line number Diff line number Diff line change
Expand Up @@ -115,66 +115,27 @@ proc rotate(canon: var Canon, rad = degToRad(canonRotationDeg)) =
proc rotateBack(canon: var Canon, rad = degToRad(canonRotationDeg)) =
canon.rotate(-rad)

## Loads the simulation
proc load*(state: var ParabolaState) =
# Render all MathJax expressions asynchronously
MathJax.typesetPromise()

# Load wrap's plugin and load matter aliases to point to the correct values
Matter.use("matter-wrap")
loadMatterAliases()

state.canvas = getElementById("canvas")
state.engine = createEngine(JsObject{gravity: JsObject{x: 0, y: 1, scale: 0.001}, timing: JsObject{timeScale: timeScale}})
state.render = createRender(JsObject{
canvas: state.canvas,
engine: state.engine,
options: JsObject{
width: state.canvas.clientWidth,
height: state.canvas.clientHeight,
showAngleIndicator: false,
showSleeping: false,
wireframes: false,
background: "transparent",#"rgb(20, 21, 31)",
}
})
Render.run(state.render)

state.runner = Runner.create(JsObject{delta: deltaTime})
Runner.run(state.runner, state.engine)

# Create and add all bodies to the world
state.canon.bulletOptions.plugin = JsObject{wrap: state.wrapObject()}

state.canon.body = Bodies.rectangle(canonX, canonY, canonWidth, canonHeight, JsObject{
isStatic: true, collisionFilter: JsObject{category: 0x2, mask: 0}, label: cstring"Canon",
render: JsObject{sprite: JsObject{
texture: cstring canonTexture,
xOffset: 0, yOffset: 0
}}
})
state.canon.rotateBack(degToRad(60d))
#constraint = Constraint.create(JsObject{pointA: jsVector(0, 0), bodyB: canon})#, length: 30, stiffness: 0.1})
proc nextBulletPosition(state: ParabolaState): JsVector =
let vertice1 = state.canon.body.vertices[1]
let vertice2 = state.canon.body.vertices[2]
jsVector((vertice1.x + vertice2.x) / toJs 2, (vertice1.y + vertice2.y) / toJs 2)

state.ground = Bodies.rectangle(state.canvas.clientWidth / 2,
state.canvas.clientHeight + (groundHeight div 2), state.canvas.clientWidth * 1000,
groundHeight, JsObject{isStatic: true, label: cstring"Groubd"}
) # 350, 495, 1200
proc calcTrajectory(state: var ParabolaState) =
let pos = state.nextBulletPosition().toTuple()
let vel = state.canon.state.velocity
let g = to(state.engine.gravity.y * state.engine.gravity.scale, float) * 1750
echo (p: pos, v: vel, g: g)

state.thingy = Bodies.rectangle(500, 350, 20, 80, JsObject{isStatic: false, label: cstring"Thingy", plugin: JsObject{wrap: state.wrapObject}})
state.canon.trajectory.setLen(0)
var i = 0d
while i < 100:
let x = pos.x + (vel.x * i.float)
let y = pos.y + (-vel.y * i.float) + (g * 0.5 * (i.float ^ 2))

state.mouse = Mouse.create(state.canvas)
state.mouseConstraint = MouseConstraint.create(state.engine, JsObject{mouse: state.mouse, collisionFilter: JsObject{mask: 0}})

Composite.add(state.engine.world, toJs [state.canon.body, state.mouseConstraint,
state.thingy,
# Walls
Bodies.rectangle(350, -200, 1000, 20, JsObject{isStatic: true}), # up
# Bodies.rectangle(690, 250, 20, 500, JsObject{isStatic: true}), # right
state.ground, # down
# Bodies.rectangle(10, 250, 20, 500, JsObject{isStatic: true}), # left
])
state.canon.trajectory.add JsVector JsObject{x: x, y: y}
i += 0.5

proc loadEvents(state: var ParabolaState) =
Events.on(state.mouseConstraint, "mousedown", proc(event: JsObject) =
if Bounds.contains(state.canon.body.bounds, event.mouse.position).to(bool):
state.canon.isDragging = true
Expand All @@ -191,6 +152,7 @@ proc load*(state: var ParabolaState) =
if state.canon.isDragging:
let targetAngle = Vector.angle(canonPivot, state.mouse.position)
state.canon.rotate(to(targetAngle - state.canon.body.angle, float))
state.calcTrajectory()
)

Events.on(state.engine, "collisionStart", proc(event: JsObject) =
Expand All @@ -211,7 +173,7 @@ proc load*(state: var ParabolaState) =

if state.canon.bullets.len > 0 and state.canon.status == csFlight:
let pos = state.canon.bullet.position
print state.canon.bullet.velocity

drawArrow(state.render.context, pos.x, pos.y,
pos.x,
pos.y + (state.canon.bullet.velocity.y * toJs velocityVectorScale),
Expand Down Expand Up @@ -240,6 +202,68 @@ proc load*(state: var ParabolaState) =
)
)

## Loads the simulation
proc load*(state: var ParabolaState) =
# Render all MathJax expressions asynchronously
MathJax.typesetPromise()

# Load wrap's plugin and load matter aliases to point to the correct values
Matter.use("matter-wrap")
loadMatterAliases()

state.canvas = getElementById("canvas")
state.engine = createEngine(JsObject{gravity: JsObject{x: 0, y: 1, scale: 0.001}, timing: JsObject{timeScale: timeScale}})
state.render = createRender(JsObject{
canvas: state.canvas,
engine: state.engine,
options: JsObject{
width: state.canvas.clientWidth,
height: state.canvas.clientHeight,
showAngleIndicator: false,
showSleeping: false,
wireframes: false,
background: "transparent",#"rgb(20, 21, 31)",
}
})
Render.run(state.render)

state.runner = Runner.create(JsObject{delta: deltaTime})
Runner.run(state.runner, state.engine)

# Create and add all bodies to the world
state.canon.bulletOptions.plugin = JsObject{wrap: state.wrapObject()}

state.canon.body = Bodies.rectangle(canonX, canonY, canonWidth, canonHeight, JsObject{
isStatic: true, collisionFilter: JsObject{category: 0x2, mask: 0}, label: cstring"Canon",
render: JsObject{sprite: JsObject{
texture: cstring canonTexture,
xOffset: 0, yOffset: 0
}}
})
state.canon.rotateBack(degToRad(60d))
#constraint = Constraint.create(JsObject{pointA: jsVector(0, 0), bodyB: canon})#, length: 30, stiffness: 0.1})

state.ground = Bodies.rectangle(state.canvas.clientWidth / 2,
state.canvas.clientHeight + (groundHeight div 2), state.canvas.clientWidth * 1000,
groundHeight, JsObject{isStatic: true, label: cstring"Groubd"}
) # 350, 495, 1200

state.thingy = Bodies.rectangle(500, 350, 20, 80, JsObject{isStatic: false, label: cstring"Thingy", plugin: JsObject{wrap: state.wrapObject}})

state.mouse = Mouse.create(state.canvas)
state.mouseConstraint = MouseConstraint.create(state.engine, JsObject{mouse: state.mouse, collisionFilter: JsObject{mask: 0}})

Composite.add(state.engine.world, toJs [state.canon.body, state.mouseConstraint,
state.thingy,
# Walls
Bodies.rectangle(350, -200, 1000, 20, JsObject{isStatic: true}), # up
# Bodies.rectangle(690, 250, 20, 500, JsObject{isStatic: true}), # right
state.ground, # down
# Bodies.rectangle(10, 250, 20, 500, JsObject{isStatic: true}), # left
])

state.loadEvents()

## Reloads the simulation
proc reload*(state: var ParabolaState) =
Composite.clear(state.engine.world)
Expand All @@ -250,16 +274,13 @@ proc reload*(state: var ParabolaState) =
state.load()

## Since matter measures y from the top of the screen, here we "normalize" it so that the 0 starts at the ground
proc normalizeBulletY(state: ParabolaState, y: int, bulletRadius: int): int =
-y + (state.ground.position.y.to(int) - (groundHeight div 2) - bulletRadius)
proc normalizeY(state: ParabolaState, y: int, height: int): int =
-y + (state.ground.position.y.to(int) - (groundHeight div 2) - height)

proc fireBullet(state: var ParabolaState) =
let vertice1 = state.canon.body.vertices[1]
let vertice2 = state.canon.body.vertices[2]

let pos = JsObject state.nextBulletPosition()
let bullet = Bodies.circle(
(vertice1.x + vertice2.x) / toJs 2,
(vertice1.y + vertice2.y) / toJs 2,
pos.x, pos.y,
state.canon.bulletRadius, state.canon.bulletOptions
)

Expand All @@ -278,7 +299,7 @@ proc fireBullet(state: var ParabolaState) =
# Invert velocity y since matter's coordinates start from the top instead of the bottom
Body.setVelocity(bullet, jsVector(velocity.x / 2.5, -velocity.y / 2.5))

proc calcTrajectory(state: var ParabolaState) {.async.} =
proc calcTrajectory2(state: var ParabolaState) {.async.} =
var stop = false # Stop updating the engine

state.fireBullet()
Expand Down Expand Up @@ -338,7 +359,7 @@ proc renderTextDiv*(state: ParabolaState): VNode =
let bullet = state.canon.bullet

x = int bullet.position.x.to(float)
y = state.normalizeBulletY(int bullet.position.y.to(float), bullet.circleRadius.to(int))
y = state.normalizeY(int bullet.position.y.to(float), bullet.circleRadius.to(int))
angle = normalizeAngle(bullet.angle.to(float))
speed = state.canon.state.speed

Expand Down Expand Up @@ -372,18 +393,18 @@ proc renderSimDiv*(state: var ParabolaState): VNode =
span(class = "material-symbols-outlined", text "rotate_left")
proc onclick() =
state.canon.rotateBack()
discard state.calcTrajectory()
state.calcTrajectory()

button():
span(class = "material-symbols-outlined", text "rotate_right")
proc onclick() =
state.canon.rotate()
discard state.calcTrajectory()
state.calcTrajectory()

#button():
# verbatim parabolaIconSvg
# #img(src = "/public/img/parabola.svg", alt = "Parabola Trajectory")
# proc onclick() = discard calcTrajectory()
# proc onclick() = calcTrajectory()
# #text "Trajectory"

button():
Expand Down Expand Up @@ -430,13 +451,13 @@ proc addEventListeners*(state: var ParabolaState) =
echo $event.key
case $event.key
of "t":
discard state.calcTrajectory()
state.calcTrajectory()
of "ArrowRight":
state.canon.rotate()
discard state.calcTrajectory()
state.calcTrajectory()
of "ArrowLeft":
state.canon.rotateBack()
discard state.calcTrajectory()
state.calcTrajectory()
of "ArrowUp", " ":
state.fireBullet()
of "Backspace":
Expand All @@ -446,10 +467,11 @@ proc addEventListeners*(state: var ParabolaState) =
#of "r":
# let exercise = exercises[curExercise]
# let bullet = bullets[currentBullet]
# Body.setPosition(bullet, jsVector(exercise.pos.x, state.normalizeBulletY(exercise.pos.y)))
# Body.setPosition(bullet, jsVector(exercise.pos.x, state.normalizeY(exercise.pos.y)))
# Body.setAngle(bullet, degToRad(float(360 - exercise.angle)))
# discard calcTrajectory()
# calcTrajectory()
# exerciseStatus = csReady
#of "d":
of "d":
echo state
print state.canon.bullet
)

0 comments on commit 13abc80

Please sign in to comment.