chipmunkbasic
is a wrapper around the Chipmunk2d rigid body physics simulation library.
chipmunkbasic
is just the simulator. To actually render the positions of bodies in the simulation you’ll need to use ggplot2, cairocore or something else
Read the online documentation here
chipmunkcore
You’ll need to install the Chipmunk2d library on your system. See the README for chipmunkcore for more information
Install this package from GitHub with:
# install.package('remotes')
remotes::install_github('coolbutuseless/chipmunkcore')
remotes::install_github('coolbutuseless/chipmunkbasic')
For full code, see the vignette
Thanks to Esteban Moro for fine-tuning this simulation, and contributing his changes.
# library(chipmunkcore)
library(chipmunkbasic)
library(ggplot2)
set.seed(1)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Initialize a simulation space
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cm <- Chipmunk$new()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Add fixed segments
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cm$add_static_segment(-20, 10, -5, 0)
cm$add_static_segment( 20, 10, 5, 0)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Fetch all the segments. Use for plotting
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
segments_df <- cm$get_static_segments()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Add some circles
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (i in 1:10) {
cm$add_circle(
x = runif(1, -20, 20),
y = runif(1, 10, 50),
vx = 10 * rnorm(1),
vy = 10 * rnorm(1)
)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Get the current positions of the circles as a data.frame
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
circles <- cm$get_circles()
circles
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Prepare the directory for output images
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
root_dir <- here::here("man/figures/")
png_dir <- file.path(root_dir, "png")
unlink(list.files(png_dir, pattern = "*.png", full.names = TRUE))
for (frame in 1:45) {
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Advance the simulation
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cm$advance(5)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Get the circles in their new locations
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
circles <- cm$get_circles()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Plot everything
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p <- ggplot(circles) +
geom_point(aes(x, y, colour = as.factor(idx)), size = 4, na.rm=TRUE) +
geom_segment(data = segments_df, aes(x = x1, y = y1, xend = x2, yend = y2)) +
coord_fixed() +
# theme_void() +
theme_minimal() +
xlim(-20, 20) +
ylim(-10, 50) +
theme(legend.position = 'none')
ggsave(sprintf("man/figures/png/%04i.png", frame), p, width = 6, height = 6)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ffmpeg/gifsicle to create animations
# - create mp4 from PNG files (use in vignettes)
# - create gif from mp4 (use in github readme)
# - simplify gif with gifsicle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
root_name <- "simple"
mp4_name <- paste0(root_dir, "/", root_name, ".mp4")
tmp_name <- tempfile(fileext = ".gif")
gif_name <- paste0(root_dir, "/", root_name, ".gif")
system(glue::glue("ffmpeg -y -framerate 10 -pattern_type glob -i 'man/figures/png/*.png' -c:v libx264 -pix_fmt yuv420p -s 800x800 '{mp4_name}'"))
system(glue::glue("ffmpeg -y -i '{mp4_name}' -filter_complex 'fps=30,scale=800:-1:flags=lanczos,split [o1] [o2];[o1] palettegen [p]; [o2] fifo [o3];[o3] [p] paletteuse' '{tmp_name}'"))
system(glue::glue("gifsicle -O99 -o '{gif_name}' -k 128 '{tmp_name}'"))
unlink(mp4_name)