Post new topic    
Page «  1, 2, 3  »
Metal King Slime
Send private message
 
 PostWed Feb 19, 2020 3:27 pm
Send private message Reply with quote
I honestly overlooked which thread I was replying to! I forgot to say how wonderful it is to have these scripts. I'm impressed in general and how you can push multiple NPCs at once based on weight. They are pretty complicated, maybe not easy for most people to extend. I'm going to write my own experience of using them.
This gives me ideas for a lot of things that I want to fix or improve on the engine's side, to make these scripts work better or make improvements possible.

Yes, either you want to resume the old path from where you left off, or re-path towards the new destination, and in either case can reconstruct the path. For Blood Ledger it would be sufficient to just remember the location when pathing was interrupted, and the path segment (destination).
But it does give me ideas for more path commands: one to compute a path and append (or prepend) a new path onto the existing one, so that you can build up a path that passes through a series of waypoints. For that to actually be useful, there would also have be commands to tell an NPC or hero to follow a computed path (currently, pathfinding NPCs/heroes always recompute the path every step). But that's far from necessary, probably not worth adding right now.

What if we have just one set of path commands, instead of duplicating them for heroes and npcs? NPC references are < 0, hero caterpillar ranks are >= 0. Though that means that you wouldn't be able to use NPC IDs, unlike every other command that operates on NPCs.

I think maybe the x/y positions should be in pixels to future-proof it.
These pathing commands don't have anyting to do with "move slice with wallchecking".

Regarding diagonal walls and diamonds, I confused myself. I should have said taking a shortcut of 20 pixels, not 10 pixels. And forget about octagons for the moment.
The idea is that if there's a wall at * which can be corner-cut around, then you could move diagonally from any of A/B/C/D to any of the others except the opposite one.
Code:
 A
B*C
 D

This would be very useful for allowing movement around small obstructing objects on the map.
A diagonal wall wouldn't allow that. It would allow A to B and C to D but not A to C and B to D; or vice versa.

This is fine for tile-based movement, but how does that translate to pixel-based (e.g. "move slice with wallchecking")? It's like a superposition of two diagonal walls. It's not actually a diamond, but more like a point at the center of the tile - except that would let you overlap the tile by 10px, which shouldn't be allowed. An ordinary diagonal wall has no trouble translating to pixel-based movement.
Liquid Metal Slime
Send private message
 
 PostSun Feb 23, 2020 11:41 pm
Send private message Reply with quote
pixel-walker0013.gif
Beware the sand! (countdown displayed bottom-left)
A lot of this talk about pathfinding is going rightly over my head. I trust the two of you to make something great in due time. The concept of appending paths sounds incredible, though. Waypoints would be an awesome addition for making the paths more organic. Often the most objectively efficient path is not the most human path, as Bena touched on.

(Thank you tmc for your kind words)

In other news, an update for Pixel-Walker: foemaps!

Because I can't find any plotscripting commands for reading foemap data from maps directly, I had to use zones in their stead. That part is insignificant, the more important aspect is converting grid "steps" to pixel "steps." As is, it Pixel-Walker counts any frame on which the player has a non-zero velocity as a step. The battle countdown functions otherwise identically, according to the dictionary's explanation under "get battle countdown."
Ps. I love my wife
Red Slime
Send private message
 
 PostThu Apr 02, 2020 10:06 pm
Send private message Reply with quote
If I can give my 2 cents, I've tried it and it's surprisingly nice. As somebody who has dealt with physics and collisions before, this is my favorite part:
Code:
# Clamp diagonal speed
if(horiz <> 0 && vert <> 0) then(
  diag := (3*spd) / 4
  if(diag < 1) then(diag := 1)
  x := clampSpeed(x, diag)
  y := clampSpeed(y, diag)
)

It's so wrong, yet it's accurate to within 5%. There's absolutely nothing not to love about it and 640k of RAM and 8 directions of movement ought to be enough for anyone.

Which brings me to my main point. To help projects like this one, it would be useful if the VM, in addition to shift operators also included some fixed point math functions. I'm thinking about "Fixed point math routines" as described in the Allegro 4 manual. Especially fixmul and fixdiv would be key.

One can do wonderful stuff with those functions. Some could be emulated right now with scripts, but the whole point is that they have to be fast to be useful.
Liquid Metal Slime
Send private message
 
 PostFri Apr 03, 2020 12:21 am
Send private message Reply with quote
I had to make diagonal movement speed slowed somehow, since moving... 40%(?) faster with combined horizontal and vertical movement feels bad. I care more about things feeling decent than being perfect. Just clamping the speed to 75% the object's top speed was easiest here. It gets the effect, so I'd rather spend my time polishing other things. Plus, these scripts are open to modification. If a user wants to change the way diagonal speeds are handled, they're more than welcome to.

Anyway, I have no idea what the Allegro 4 manual is. I don't remember what fixed point math is. Haven't taken a comp sci class that covered that in years. Needless to say, I don't know how they relate. What's the "correct" way to deal with diagonal speed boosts?

EDIT: God, I'm reading about fixed point arithmetic and having flashbacks to discrete math class. *shudder*
Ps. I love my wife
Red Slime
Send private message
 
 PostFri Apr 03, 2020 6:12 pm
Send private message Reply with quote
Quote:
I don't remember what fixed point math is ... I don't know how they relate.

Suppose you want your object to accelerate by 0.5 pixels/s^2. I'm not saying you did anything wrong, it's just that you don't have much choice of parameters because of the integer arithmetic.
Quote:
What's the "correct" way to deal with diagonal speed boosts?

Pythagora's theorem.
Quote:
I have no idea what the Allegro 4 manual is.

It's a library that used to be popular during the golden age of dos games. Anything more recent uses floating-point numbers, but they're not supported by the scripting VM. Support for fixed-point numbers could be patched in and it would allow games such as billiard or minigolf.

----

Because I'm still under quarantine and I have nothing better to do, I've written a very minimal 24.8 fixed point library:
Code:
script, fix24:from, a
    return(a * 256)
end
script, fix24:mul, a, b
    return(multdiv(a, b, 256))
end
script, fix24:div, a, b
    return(multdiv(a, 256, b))
end
script, fix24:to, a
    return(a / 256)
end

The problem is that it's prone to overflow it's legit now, but due to the limited screen coordinates, it works and it may be useful. I'll publish a demo later but in the meantime, this is a minimal inertia-like setup:
Code:
# starting position
blpx = fix24:from(100)
blpy = fix24:from(100)

while(true) do (

# read the input or do a collision check
# to modify the acceleraton

# apply acceleraton
blvx += blax, blvy += blay

# apply velocity
blpx += blvx, blpy += blvy

# apply friction
blvx = fix24:mul(blvx, 240)
blvy = fix24:mul(blvy, 240)

put slice(chandle, fix24:to(blpx), fix24:to(blpy))

wait(1)
)

It's enough to play soccer with a slice. The point is that the code above can move objects at fractional speeds and speeds less than 1. A fix16 library would be much more precise, but this is what's feasible now.
Metal King Slime
Send private message
 
 PostSat Apr 04, 2020 12:21 am
Send private message Reply with quote
Kylekrack has been posting previews of some great new features in discord!

There already is a multdiv function (it's not a math function), which is basically what you want. multdiv avoids overflow of intermediate result, and rounds the result (which is usually what you want). It isn't documented in the plotdictionary out of laziness because I didn't expect anyone would find it useful, but I see I was wrong, and I should add it.
Code:
649,multdiv,3,0,0,0           # calculate int(float(a)*b/c), with rounding and clamping (undocumented)

For example fix24:mul(1000, 10000) would overflow but you could rewrite it as multdiv(1000, 10000, 256).
96% of the time performance is irrelevant, but if you actually cared about it, the overhead of calling a script call is relatively huge* so you wouldn't want to use wrapper scripts. This is one reason why I want to add macros to HS.


* Trivia: in the early DOS days, every time a script was called it was loaded from disk... and DOS doesn't have a file cache.
Red Slime
Send private message
 
 PostSat Apr 04, 2020 12:29 am
Send private message Reply with quote
Code:
the overhead of calling a script call is relatively huge

I'm never going to do physics on more than one object for now, also because of the lack of arrays. But it could be enough for a minigolf.

----

So, there's a little bit of a "pick your poison" type of situation with the "multdiv" function because the conversion to float causes a loss in precision and the rounding causes objects to never stop sliding.

If possible that function should be modified to use an int64 as intermediate type and use no rounding. It's nothing dramatic anyway, but with it you need an extra check for when the object is declared to be at rest.
Metal King Slime
Send private message
 
 PostSun Apr 05, 2020 5:04 am
Send private message Reply with quote
The script interpreter isn't terribly slow. On a very small set of benchmarks (testgame/benchmark.py and benchmark.rpg), it's 1-3x slower than CPython 2, and sometimes faster than CPython 3.

Quote:
So, there's a little bit of a "pick your poison" type of situation with the "multdiv" function because the conversion to float causes a loss in precision and the rounding causes objects to never stop sliding.

There you go, thinking like a C programmer again. Here, "float" doesn't mean single precision, it means double precision. (No-one uses singles for intermediate results!) Now of course a double only has 53 bits of precision, but the return value has only 32 bits, so that's enough.

I don't see why rounding wouldn't be desired in the large majority of cases or why it causes a problem for your script specifically
Red Slime
Send private message
 
 PostSun Apr 05, 2020 9:41 am
Send private message Reply with quote
Code:
why it causes a problem

Because your "multdiv" function says that 80% of 1 is 1. Your divide operator instead says that 80% of 1 is 0. It's not a problem, it's just that truncates towards zero, which in this particular case happens to be the right thing to do.

However, your division operator can't be used in place of an arithmetic shift. Consider this in Python3:
Code:
>>> 1 // 2
0
>>> -1 // 2
-1

The normal behavior for integer division is to truncate toward negative infinity like floor for floats. The reason is that (x / 2) is supposed to be the same as (x >> 1). Your division operator returns 0 for -1 / 2.

Aren't integer numbers amazing?
Liquid Metal Slime
Send private message
 
 PostSun Apr 05, 2020 8:38 pm
Send private message Reply with quote
pixel-walker0016.gif
Non-square Talkbox
pixel-walker0017.gif
Multiframe, directional Idle Animations
pixel-walker0019.gif
"Meandering" chase AI
pixel-walker0020.gif
Pushability bits
pixel-walker0024.gif
Caterpillar party members!
Well, I'm thoroughly lost! I'd love to get fractional speeds in there, but I'm going to address getting a fully functional script set before returning to the physics. They work so adequately, for now, that'd it'd be a silly prioritization to rework them at the moment. That may be closer to the present than I thought, though, as I've added a lot of features in Pixel-Walker 2.3 that I was dreading.

On that note, here are some of those gifs tmc mentioned. Some of these things have apparent bugs (while others have thus far hidden ones), but typically either have workarounds or can be disabled.

The "talkbox" that collides with NPC slices and determines interactability now has independent width and height and will change dimensions to align with player direction. When facing diagonally, the width and height are averaged, making the talkbox a square. This way, it doesn't favor the x or y axis.

You can set a separate spriteset and frame count for hero/NPC idle animation. Additional frames beyond the initial idle animation frame are sequential in the sprite editor. Eg. an NPC that has a 3-frame idle animation that starts at spriteset 11 will go: Set 11 > Set 12 > Set 13 > Set 11 > ... The spriteset can be set to -1 for heroes/NPCs you don't want to idle.

Chase and Avoid NPC behaviors now differentiate between meandering and direct. "Meandering" in this case means that NPCs have a 25% chance of choosing a random direction instead of the direction towards the player.

Pushability can now be set to Full, Vertical, Horizontal, Up only, etc. This may not behave entirely as intended due to a lack of friction with hero-NPC collision. This will be fixed eventually. Basically, you can push a Vertical pushable NPC from the side by moving into it horizontally, and then moving diagonally (up or down).

Caterpillar party members was probably the most challenging, and presented the most problems. It works now, if you never rearrange the party. However, adding heroes is finicky, and swapping heroes in the Order and Team builtin menus *will* cause problems in hero sprites/animations. Looking into a solution, but it may require changes to the engine to truly fix.
Ps. I love my wife
Liquid Metal King Slime
Send private message
 
 PostMon Apr 06, 2020 12:11 am
Send private message Reply with quote
Caterpillar party is beautiful! Great job!

I like the talk box visualizations too
Chemical Slime
Send private message
 
 PostWed Apr 08, 2020 6:12 pm
Send private message Reply with quote
Great stuff! I like all the new features. *looks at extended idle animations longingly*
Liquid Metal Slime
Send private message
 
 PostThu Apr 09, 2020 10:10 am
Send private message Reply with quote
Making frames of animation sequential spritesets has actually worked out quite elegantly. I'm sure it makes adding frames to existing sprites an absolute pain, but it's not impossible. It effectively makes framecount limitless, without doing any wackiness like the standard 3-frame walking script.

Wait... could the 3-frame walking script be extended just by adding more sets and looping through them via modulo, rather than a simple toggle..?

I digress. Point is, the walkabout sets are 8-frames long, which makes 8-directional sets quite straightforward. That being said, part of me is dreading when the OHR gets support for custom framecounts and this all becomes obsolete.

EDIT: Bob, your words are kind and very meaningful. Caterpillar mode was hard but I'm very happy I powered through it.
Ps. I love my wife
Liquid Metal Slime
Send private message
 
 PostMon Apr 20, 2020 6:43 am
Send private message Reply with quote
Version 2.3 is up for download:
https://www.slimesalad.com/forum/viewtopic.php?p=130697#130697

After battling with proper NPC collision for 2 straight days, I decided I should checkout back to my master branch and release v2.3 as is. Collisions are, to put it lightly, an absolute waking nightmare. I made progress that was so buggy, I'm not even sure it could be considered progress, since the code is so broken that it'll likely need to be scrapped and written from scratch anyway. Perhaps it will be a learning experience. I've learned that I'm better off pestering TMC to add slice collisions to existing wallchecking script commands. In all seriousness, I'm not going to attempt proper NPC collisions on my own, beyond what's already in the scripts, without someone's direct help.

All of the gifs in my previous post should cover most of what's new in this version. The other details worth mentioning are some fairly nasty bugs that I need to address before these scripts can be considered safe to use.
Ps. I love my wife
Red Slime
Send private message
 
 PostMon Apr 20, 2020 6:38 pm
Send private message Reply with quote
kylekrack wrote:
Collisions are ... an absolute waking nightmare.

In between feeling really bad because of this quarantine, I've written some slice-pass block collision code that works with the simple physics we've discussed earlier. This is the idea:
Code:
variable(pbx, pby, pbs)
pbx = fix24:to(blpx) / 20
pby = fix24:to(blpy) / 20
pbs = read pass block(pbx, pby)

variable(pb1x, pb1y, pb2x, pb2y, pbd, pbdx, pbdy)
pb1x = fix24:from(pbx * 20)
pb1y = fix24:from(pby * 20)
pb2x = fix24:from((pbx + 1) * 20)
pb2y = fix24:from((pby + 1) * 20)

# north wall
if (pbs & bit:lshift(1, 0)) then (
   pbd = blpy - pb1y
   if (pbd <= blrad) then (
      blpy += blrad - pbd
      blvy = -fix24:mul(blvy, 50)
   )
)
...

There are 8 cases you need to check in total after the north wall case. 4 walls and 4 corners need to be checked if you want to do it properly. So it gets rather long. But it can be done if you want to.
Display posts from previous:
Page «  1, 2, 3  »