11

Cart #spline-2 | 2022-10-01 | Code ▽ | License: CC4-BY-NC-SA
11

This is a tool for creating and editing splines within your game. I used this initally for a shmup i was working on where I wanted to create an intresting enemy flight pattern.

The black area represents a 128x128 screen.

Just click in the points you want then press CTRL+C to copy to clipboard This will copy all points to the clipboard as a string.

This string can be then used within your game.

This is what I use it for.

You can test out pasting of splines here. Also this cart has code for handling the splines.

Cart #spline_demo-0 | 2022-10-01 | Code ▽ | No License
11

# How to use

copy the following code to your cart (this can also be read from tab 2 of the demo cart)

 ```--distance vunerable to overflow function pdist(p1,p2) return ((p2.x-p1.x)^2+(p2.y-p1.y)^2)^0.5 end --cubic bezier single dimension function cub_b_p(a,b,c,d,t) local tm=1-t return tm*tm*tm*a+ tm*tm*3*t*b+ tm*3*t*t*c+ t*t*t*d end --cubic bezier x&y function cub_bez(p1,p2,p3,p4,t) return {x=cub_b_p(p1.x, p2.x, p3.x, p4.x, t), y=cub_b_p(p1.y, p2.y, p3.y, p4.y, t)} end --read splines --expected table with multiple --of 8 entries. --p1.x,p1.y function read_spline(points) local curves,dists,td={},{},0 local limits={0} for i=1,#points,8 do local pts={} for j=i,i+8,2 do add(pts, { x=points[j], y=points[j+1]}) end local function c(t) return cub_bez( pts[1], pts[2], pts[3], pts[4], t) end local d=0 for j=0x0.1,1,0x0.1 do d+=pdist(c(j-0x0.1),c(j)) end add(curves,c) add(dists,d) td+=d end local l=0 for d in all(dists) do l+=d/td add(limits,l) end limits[#limits]=1 local function spl(t) if t==1 then return curves[#curves](1) end local i,l=1,0 while t>=l do i+=1 l=limits[i] or 1 end local ol=limits[i-1] local fact=1/(l-ol) local t2=(t-ol)*fact return curves[i-1](t2) end --return curves return spl end ```

## 2 Generating curves

Generate curves using the main cart that represent how you would like your mobs to move. Just click different points into place. Note that the black area represents a whole screen of 128x128 pixels.

You can click and drag points around, press delete to delete the last point. When you are happy with your curve press CTRL+C to copy a string to the clipboard.

NOTE: Sometimes the string doesn't copy correctly in the web player, if this happens from pico-8 you can `load #spline` and run the cart locally. The copy seems far more reliable when running in pico-8

Paste the following into your `_init()` function.

`path=read_spline(split(*your pasted string*))`

Then whenever you want a point along the path you just call path using the decimal of what portion of the path you want covered.

## examples

`local point = path(0)` Will give you the start point of the path
`local point = path(0.25)` Will give you a point 1/4 the way through the path.
`local point = path(1)` Will give you a point at the end of the path.

 ``` local point = path(0.5) --half way spr(1, point.x, point.y) --draw sprite 1 at this point.```

Feel free to look at the demo cart for code that uses a sprite.

# Update

Now cart accepts pasting of splines not just upload.
Now curves are more round by default

# Credits

Thanks to @pancelor for the idea about the splines.
Thanks to @Heracleum for assistance writing up how to use the cart.

P#117952 2022-09-25 17:35 ( Edited 2022-10-01 22:09)

Man, I never thought about this, but pico 8 NEED a path editor. Kinda like the path editor from game maker. This does the work very well. Gold star.

P#117956 2022-09-25 18:12

How would I use the exported data?

P#118251 2022-09-30 23:32
1

@spellcaster there are multiple ways that this can be read. The approach I take is as follows.

 ```--read splines --expected table with multiple --of 8 entries. --p1.x,p1.y function read_spline(points) local curves,dists,td={},{},0 local limits={0} for i=1,#points,8 do local pts={} for j=i,i+8,2 do add(pts, { x=points[j], y=points[j+1]}) end local function c(t) return cub_bez( pts[1], pts[2], pts[3], pts[4], t) end local d=0 for j=0x0.1,1,0x0.1 do d+=pdist(c(j-0x0.1),c(j)) end add(curves,c) add(dists,d) td+=d end local l=0 for d in all(dists) do l+=d/td add(limits,l) end limits[#limits]=1 local function spl(t) local i,l=1,0 while t>=l do i+=1 l=limits[i] or 1 end local ol=limits[i-1] local fact=1/(l-ol) local t2=(t-ol)*fact return curves[i-1](t2) end --return curves return spl end --distance vunerable to overflow function pdist(p1,p2) return ((p2.x-p1.x)^2+(p2.y-p1.y)^2)^0.5 end --cubic bezier single dimension function cub_b_p(a,b,c,d,t) local tm=1-t return tm*tm*tm*a+ tm*tm*3*t*b+ tm*3*t*t*c+ t*t*t*d end --cubic bezier x&y function cub_bez(p1,p2,p3,p4,t) return {x=cub_b_p(p1.x, p2.x, p3.x, p4.x, t), y=cub_b_p(p1.y, p2.y, p3.y, p4.y, t)} end```

Take the array of points. Every number represents X,y pairs.

For every four pairs represents a segment. I run this through the function `cub_bez()` with a t between 0 and 1 which represents 0 is at the first point of the segment 1 is at the end point of the segment.

Depending on what you want to do this may be enough. However I'm using it for motion therefore I want to normalize all of this so that each segment is the same speed.

To do this I sample each curve segment multiple times and get a sum of the distance between each of the points.

I then add all of these together and produce a new function that takes a value between 0 and 1 that represents the entire spline as a single function.

This function is returned from the `read_spline` function below.

P#118282 2022-10-01 14:46