Javis collision detection

So I’m using the excellent package Javis.jl where I’m making a small simulation to teach my kids about entropy. Basically I want a box with a number of of balls bouncing around in it. I want to be able to detect when the balls collide with each other or with the walls of the box but i cannot see how to do it using the existing translate function. Has anyone tried something similar? The only way that came to me was to precalculate all the trajectories but there must be a better way i believe.

1 Like

I confess I’ve not used Javis, but I think you’d just update and collision-check the positions of each ball after each frame. I’ve done similar with Luxor:

julia-billiard-pool

so it should be easier in Javis.

@Wikunia or @TheCedarPrince would be happy to help, so I’ll mention them here.

5 Likes

Thank you so much for the reply, this sets me on the right path I think. I have a small example for 1 ball here

using Javis

function ground(args...)
  background("white")
  sethue("black")
end

function object(p=O, color="black")
  sethue(color)
  circle(p, 25, :fill)
  return p
end

function updatedirection!(bpos)
end

myvideo = Video(500, 500)
Background(1:70, ground)
redball = Object(1:70, (args...) -> object(O, "red"), Point(-250, -250))
Object(1:70, (args...) -> updatedirection!(pos(redball)))
act!(redball, Action(anim_translate(300, 300)))
render(myvideo; pathname="entropy.gif")

But the thing here is that I don’t know what to put in updatedirection! I’m assuming it should update the position of the ball but just accessing the x and y fields in the struct is not allowed so I guess I need a function to mutate these states somehow.

Not sure about Javis per se, but you can change points stored in a mutable struct:

ball.pos = Point(ball.pos.x + 1, ball.pos.y)

Ahh… I was trying to update the x directly. Thanks!

I was too fast, upon testing this I cannot get it to work.

function updatedirection!(ball)
  ball.pos = Point(-ball.pos.x, ball.pos.y)
  ball
end

myvideo = Video(500, 500)
Background(1:70, ground)
redball = Object(1:70, (args...) -> object(O, "red"), Point(-250, -250))
Object(1:70, (args...) -> updatedirection!(redball))
act!(redball, Action(anim_translate(500, 500)))
render(myvideo; pathname="entropy.gif")

It seems that redball does not have a .pos field so I cannot set it to a new Point. I must misunderstand completely how the underlying state is handled in Javis.

This is the error:

ERROR: type Object has no field pos
Stacktrace:
  [1] getproperty
    @ ./Base.jl:38 [inlined]
  [2] updatedirection!(ball::Object)
    @ Main ./REPL[73]:2
  [3] (::var"#29#30")(::Video, ::Vararg{Any})
    @ Main ./REPL[77]:1
  [4] draw_object(object::Object, video::Video, frame::Int64, origin_matrix::Matrix{Float64}, layer_frames::Nothing)
    @ Javis ~/.julia/packages/Javis/UaLm7/src/Javis.jl:666
  [5] macro expansion
    @ ~/.julia/packages/Javis/UaLm7/src/Javis.jl:416 [inlined]
  [6] macro expansion
    @ ~/.julia/packages/Luxor/HNu4m/src/basics.jl:576 [inlined]
  [7] render_objects(objects::Vector{Javis.AbstractObject}, video::Video, frame::Int64; layer_frames::Nothing)
    @ Javis ~/.julia/packages/Javis/UaLm7/src/Javis.jl:415
  [8] render_objects
    @ ~/.julia/packages/Javis/UaLm7/src/Javis.jl:387 [inlined]
  [9] get_javis_frame(video::Video, objects::Vector{Javis.AbstractObject}, frame::Int64; layers::Vector{Javis.AbstractObject})
    @ Javis ~/.julia/packages/Javis/UaLm7/src/Javis.jl:609
 [10] render(video::Video; framerate::Int64, pathname::String, liveview::Bool, streamconfig::Nothing, tempdirectory::String, ffmpeg_loglevel::String, rescale_factor::Float64, postprocess_frames_flow::typeof(identity), postprocess_frame::typeof(Javis.default_postprocess))
    @ Javis ~/.julia/packages/Javis/UaLm7/src/Javis.jl:291
 [11] top-level scope
    @ REPL[79]:1

cormullion was just giving an example , but Javis objects dont have a pos field.
the position of the object is obtained using the get_position function on the object.
while there is no “set_position” the position is changed through the actions.

I think anim_translate is probably not the right function since it calculates the starting position and the ending position of the translation before the rendering starts . I dont know if there is a way currently to change the direction of the anim_translate midway through the animation.

What you could try doing is , move every object by a small amount - frame by frame.
every object can have a “velocity” the distance and direction it moves every frame.
updatedirection! can then run through all pairs of objects detect collisions and change the “velocity”

You can hold velocity state in the opts field which is a dictionary

2 Likes

The following code only checks for collision with the vertical walls .

using Javis
video = Video(500,500)
nframes=250
Background(1:nframes, (v,o,f)-> background("white"))

obj = Object(1:nframes , (v,o,f)-> begin 
                    circle(O,50,:fill)
                    return O 
                end)
obj.opts[:velocity] = (10,1)

#not really an obj , as in draws nothing , but runs a function
updaterobj = Object(1:nframes , (v,o,f) -> begin
                        #hardcoded boundaries of the video
                        if !(-250+25 < get_position(obj).x < 250-25)
                            v = obj.opts[:velocity]
                            obj.opts[:velocity] = (-v[1],v[2]) 
                        end
                    end)

move() = (v,o,a,f)-> begin
    if f == 1
        #need this if since get_position doesnt work on frame 1
        translate(o.start_pos + o.opts[:velocity] )
    else
        translate(get_position(o) + o.opts[:velocity] )
    end
end

act!(obj , Action(1:nframes,move()))

render(video,pathname="vid.mp4")
run(`mpv vid.mp4`)
6 Likes

Wow great, that was really far away from what I was trying. Didn’t know that I could use the opts for state management. Thank you for this example it would have taken me forever to figure this out. :rofl:

vid

Discourse was bugged out a bit , couldnt upload the gif earlier ,

Anyway just be careful while using opts , its used internally in Javis for some purposes ,
opts[:result] is one which i know is used .
So dont use keys with those names. In the future if you want to be safe(er) give a prefix to your keys something like
pfx_keyname

1 Like

@DoktorMike if you’re willing to , then do submit what you come up with for the example gallery on Javis.jl github repo .

2 Likes

@arbitrandomuser Done: Added an example for entropy simulation. by DoktorMike · Pull Request #493 · JuliaAnimators/Javis.jl · GitHub

3 Likes