Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Corla Plankun
May 8, 2007

improve the lives of everyone
UGH Of course as soon as I post it occurs to me to check to see if the bug exists in the "completed" version of the game in the assets, and it doesn't. Because THEIR Player prefab has the "Simulated" checkbox checked.

Adbot
ADBOT LOVES YOU

The Fool
Oct 16, 2003


Corla Plankun posted:

UGH Of course as soon as I post it occurs to me to check to see if the bug exists in the "completed" version of the game in the assets, and it doesn't. Because THEIR Player prefab has the "Simulated" checkbox checked.

welcome to development

cultureulterior
Jan 27, 2004
A dedicated unity thread might be nice- I would be able to have somewhere to complain about dots physics but I think it would be sparsely used

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
This and the Making Games megathread get plenty of Unity bitching, it's fine.

Purple Prince
Aug 20, 2011

TooMuchAbstraction posted:

This and the Making Games megathread get plenty of Unity bitching, it's fine.

One thing from an architecture standpoint that I don't understand about Unity is it's not fully an entity-component system nor a object oriented system, so you have to cludge together your own systems for managing components and objects, which are sort of the same but not really. This gets particularly awkward with event driven stuff like UIs where you might want to chain a number of events on your model and your view together - but, surprise, the view and the model are encapsulated and have no default way of talking to each other.

Is there an idiomatic way of managing this or is it just winging it in various ways that work?

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Purple Prince posted:

One thing from an architecture standpoint that I don't understand about Unity is it's not fully an entity-component system nor a object oriented system, so you have to cludge together your own systems for managing components and objects, which are sort of the same but not really. This gets particularly awkward with event driven stuff like UIs where you might want to chain a number of events on your model and your view together - but, surprise, the view and the model are encapsulated and have no default way of talking to each other.

Is there an idiomatic way of managing this or is it just winging it in various ways that work?

Unity ECS is very much a full ECS.

The older workflow is explicitly not ECS, and you shouldn't conceive of entities, components, and systems. The cleanest way I know of to work with behaviors is basically MVVM. Have your top-level view have a behavior for the view (this is your view model). It internally interfaces with the model. The rest of the view is comprised of GUI elements that callback into the view model for which the view model holds private serialized fields.

Unity wasn't really built to handle creating and removing monobehaviours at runtime. Doing so usually lead to perf issues and generally feeling like the engine isn't pulling its weight.

For event driven stuff, Ryan Hipple had a talk a few years back going over a setup serializing unity events (the same type used by unity's button) onto scriptable objects.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
This is a continuation of my suffering that you might have had to see in the gamedev Discord. I figured out that after updating Unity to 2019.2.17f1 and VS2019 that I could not longer step into my own DLLs. My workflow is to copy the .dlls and .pdbs into Assets/References, let Unity munge on them (generate .mdbs), attach, then start the scene. Usually that's enough. VS2019 definitely is reporting that it can't find the symbols.

Last night, it wouldn't even let me explicitly load symbols. The dialog wouldn't bother to come up. Manually setting symbol paths was useless. I ultimately just set VS2019 to update overnight. Today, I figured out one important thing: apparently you need to build your PDBs as portable PDBs:

https://forum.unity.com/threads/automated-mdb-generation.755237/

This wasn't enough to solve my problem. I made those changes for the projects I was trying to step in particular, and I still couldn't step in. On the other hand, I finally got the old file dialog when trying to load symbols. VS2019 just refused to recognize the .pdb file was being the one it wants.

On the other hand, if I open the project for the external DLL and attach to Unity from there, I can walk around in my own code just fine. I just can't go back and forth with the Unity project and the code in the DLL, which is frustrating because I'm debugging integration right now.

I did this update a few months ago, and I think it first started then, but I treated it as basic upgrade pains and it wasn't really getting in the way. I just dealt with it at that time.

I've also generally noticed that there's a lot of pain and suffering trying to attach. Usually this manifests as Unity hanging until I disconnect the debugger. Sometimes it works afterwards. Should I move off that particular Unity version?

I should also note that I have VS2017 and an older version of Unity still sitting around in case that can be causing interference. I'm not actively using them, but who knows?

more falafel please
Feb 26, 2005

forums poster

Rocko Bonaparte posted:

This is a continuation of my suffering that you might have had to see in the gamedev Discord. I figured out that after updating Unity to 2019.2.17f1 and VS2019 that I could not longer step into my own DLLs. My workflow is to copy the .dlls and .pdbs into Assets/References, let Unity munge on them (generate .mdbs), attach, then start the scene. Usually that's enough. VS2019 definitely is reporting that it can't find the symbols.

Last night, it wouldn't even let me explicitly load symbols. The dialog wouldn't bother to come up. Manually setting symbol paths was useless. I ultimately just set VS2019 to update overnight. Today, I figured out one important thing: apparently you need to build your PDBs as portable PDBs:

https://forum.unity.com/threads/automated-mdb-generation.755237/

This wasn't enough to solve my problem. I made those changes for the projects I was trying to step in particular, and I still couldn't step in. On the other hand, I finally got the old file dialog when trying to load symbols. VS2019 just refused to recognize the .pdb file was being the one it wants.

On the other hand, if I open the project for the external DLL and attach to Unity from there, I can walk around in my own code just fine. I just can't go back and forth with the Unity project and the code in the DLL, which is frustrating because I'm debugging integration right now.

I did this update a few months ago, and I think it first started then, but I treated it as basic upgrade pains and it wasn't really getting in the way. I just dealt with it at that time.

I've also generally noticed that there's a lot of pain and suffering trying to attach. Usually this manifests as Unity hanging until I disconnect the debugger. Sometimes it works afterwards. Should I move off that particular Unity version?

I should also note that I have VS2017 and an older version of Unity still sitting around in case that can be causing interference. I'm not actively using them, but who knows?

I'm only using Unity on consoles at the moment (and 2018 at that) but my experience is that debugging kinda works, occasionally, and for no reason, then stops working again. I don't care for Unity.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!

more falafel please posted:

I'm only using Unity on consoles at the moment (and 2018 at that) but my experience is that debugging kinda works, occasionally, and for no reason, then stops working again. I don't care for Unity.

Ugh that's not really reassuring.

New wrinkle, apparently the modules view can't even be trusted:
https://developercommunity.visualstudio.com/content/problem/743444/visual-studio-randomly-refuses-to-load-symbols-whe.html

quote:

When debugging a Unity project, Visual Studio will never try to load symbols. In fact as Unity is using the Mono runtime, their debugger agent -hosted in the Mono runtime- is responsible for doing that and we only connect to it for the actual debugging. So the “modules” window is not accurate for the Unity scenario.

So I might not even be seeing the actual situation!

Edit: The saga continues. When I was stepping through the code from the external DLL's project, it was trying to tell me that, like, everything was null. I'd look up a string in an array and get null. I'd inspect the array and nothing was null. I tried it in the immediate window and got the expected result. So I'm thinking I need to drop a bomb on the whole installation.

Rocko Bonaparte fucked around with this message at 16:52 on Apr 3, 2020

LordSaturn
Aug 12, 2007

sadly unfunny

Purple Prince posted:

One thing from an architecture standpoint that I don't understand about Unity is it's not fully an entity-component system nor a object oriented system, so you have to cludge together your own systems for managing components and objects, which are sort of the same but not really. This gets particularly awkward with event driven stuff like UIs where you might want to chain a number of events on your model and your view together - but, surprise, the view and the model are encapsulated and have no default way of talking to each other.

Is there an idiomatic way of managing this or is it just winging it in various ways that work?

I dunno about idiomatic, but as someone who spends a lot of time making turn-based, grid-based games in Unity, I've adopted certain habits w.r.t. how to organize things. My idiom is a mixture of classical OOP and egregious abuse of the power and convenience of the Unity editor - it is always easier to just connect a reference in the editor manually, than to track it down programmatically.

Broadly speaking, if you have a monobehaviour that you need to find from another monobehaviour at runtime, your options are: (in approximate order of my preference)
  • Add a reference variable on the monobehaviour you're seeking from, and populate it manually in the editor.
  • Make it a "singleton" monobehaviour. Not a real C# singleton, Unity singletons are much simpler:
    code:
    public class MySingleton : MonoBehaviour
    {
        public static MySingleton instance { get; private set; }
    
        void OnEnable()
        {
            // Become the instance...
            if (instance == null)
            {
                instance = this;
            }
            // ... or self-destruct.
            else
            {
                Destroy(gameObject);
            }
        }
    
        void OnDestroy()
        {
            // If we were the instance, clear the instance
            if (instance == this)
                instance = null;
        }
    }
    
  • Arrange your scene so that the thing you're looking for is always above you in the transform hierarchy, so that GetComponentInParent will do the job relatively cheaply. (Cache the result if possible.)
  • Use FindObjectOfType. (Cache the result if possible.)

So for my GUI needs, I have a singleton GUI Controller monobehaviour in each scene, which contains reference variables pointing to the various GUI controls in the scene. These have a common ancestor, GuiEventAggregator, which just contains an event and a method to call that event. The event takes a GuiElement as an argument; GuiElement is the common ancestor of all my GUI controls. GuiElement contains a bit of boilerplate to simplify showing/hiding/moving GUI stuff during gameplay, and a protected no-arguments void function called SendEvent that pretty much does:
code:
GetComponentInParent<GuiEventAggregator>().HandleEvent(this)
You'll notice this employs three distinct strategies from the four listed above. This is because I have three distinct problems to solve:
  1. Every GUI button, checkbox, etc needs to be able to tell the current scene's GUI handler, "Hey, something happened over here."
  2. The state machine that handles menus, input states, etc needs to be able to find the scene's GUI handler to add/remove event handlers from its event.
  3. The event handlers in the state machine need to be able to identify which control an event was from, and also need to be able to show/hide/move controls in response to state changes.

So for a GUI element like a button, I have a GuiTextButton monobehaviour that descends from GuiElement, and has a little bit of code to automatically attach SendEvent to the Button script's OnClick. (Also some stuff to make it easy to change the button's text.) The GuiElement code will automatically route these events to the scene's GUI Controller.

The state machine accesses the GUI controller's instance variable, and from there it can find references to all the GUI elements in the scene, as well as an event handler to receive GUI events and respond to them.

I hope this helped anyone. Adding new stuff to this system is a bit of a chore, but way easier than trying to accomplish the same things without the system, and it would probably be easier if I'd sit down and integrate all this crap into the Unity GUI menus. I'd also like to ever finish the vertical slice of this game to show it off here. :)

baby puzzle
Jun 3, 2011

I'll Sequence your Storm.
I've been stuck in the dev cave, working on new features for my really cool rhythm game.

https://www.youtube.com/watch?v=TU62pKcs4Pk

- Game speed changes authored into the track. This track starts at 50% speed but then jumps up to 100% at the "drop."
- Lanes that prompt you to steer your vehicle back and forth, in time with the music. There is a lot of "help" here but it is intended to provide a cool analog feel, even when playing on keyboard.
- Track in the shape of a cylinder, which gives a very intense experience.
- oh and camera angle changes authored into the track.

e: all the new graphics and effects are in a beta state here. I know what looks janky.

baby puzzle fucked around with this message at 19:53 on Apr 3, 2020

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense

baby puzzle posted:

I've been stuck in the dev cave, working on new features for my really cool rhythm game.

I'm glad the problem of rhythm games being too easy has been solved. I always felt I needed 5 more buttons and a steering mechanic to bring it into line with the difficulty I face in day to day life.

cultureulterior
Jan 27, 2004
So Unity DOTS is cool, but I really wish I was two years down the line and everything was stable and working with good documentation. Pretty great to finally have a good way of writing multithreaded code though.

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Making games is so difficult. And then nobody appreciates the work that goes into them because they've seen it before.

Like, just working out my point of interest system, that's being used by the ai. To keep track of where they might want to go to excavate an area, or build a feature, whether the space a feature is going to take up has been fully excavated, where items that are sitting around are located.

The system needs to keep track of not only where they need to be but what neighbouring tile they're facing once they get there. Whether the tile they're headed to is in use by someone else. Trying to keep it simple and still coherent to me, is hilarious.

Fidel Cuckstro
Jul 2, 2007

I'm learning Unity with all this quarantine free-time, and trying to make a small game. Wondering if anyone can help me identify the name of the mechanic/system I'm looking to build, because it seems like it's not particularly unique and I imagine someone's put together some tutorials on how to build something like it.

I'm trying to do something similar to the story mission mechanic in a game like Stellaris- where missions will appear on a map over time. The player moves pieces to the missions and can assign them to start. Once started, the piece is locked in place and starts a countdown and success/failure roll to an eventual completion state.

Any thoughts on places to look?

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
That sounds pretty specialised to me. If something like AI hasn't been standardised I wouldn't think a mission system would be, is there something about it that you're having difficulty with right now?

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I reinstalled VS2019, started a new Unity project, and fed it a DLL I built with a one-liner static method to return an integer. I couldn't even step into that with neither full nor portable PDBs. I think it's just broken now?

Corla Plankun
May 8, 2007

improve the lives of everyone
Maybe read a little bit about State Machines and try to use that model to represent the locked-in unit? I think using finite state machine vocabulary will help keep the code from turning into spaghetti.

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
I shared this on discord as well, but figured y'all'd get a kick out of it too:



It's a photo of my screen, instead of a screenshot, because my computer was completely hosed. I couldn't bring up the Task Manager to kill the process, and just moving the mouse cursor around would make the internal speaker beep, which is something I've personally never seen before. I got to this point by trying to use the deep profiler to discover the cause of a ~600MB allocation that's occurring on the first frame of the game running. This takes on the order of 20-30 seconds in the editor with profiling turned off. It turns out to take rather longer with deep profiling enabled.

Is anyone familiar with Unity's Profiler API? I was hoping there'd be something that would give me a value I could relate to the "GC Alloc" column in the profiler, so I could narrow my search with debug logging. Neither GetMonoHeapSizeLong nor GetTotalAllocatedMemoryLong seem to be that.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
You mention this allocation happens "on" the first frame ... Does that mean it has not yet happened when your first bit of code for that frame runs?

If so, you could consider setting a breakpoint there, and then capturing a profile of just the first frame itself, not any of the startup stuff.

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
I'm leery of trying to rely on the deep profile for this, given that last time I had to hard power cycle my computer. But to clarify: it happens in the course of running Start code, before the first frame is rendered. It didn't use to happen; maybe a few weeks ago a change got introduced that added it, I think. I guess I could git bisect to figure out what the change is, but that's pretty laborious.

By dint of short-circuiting my startup code and looking at how that affects allocations, I've been able to narrow things down to some extent. I have a library of 3D models and associated stat blocks and particle systems, and when it's asked to retrieve data on a model it hasn't loaded, it loads everything (Past Me wasn't thinking about how this scales). The weird thing is that this isn't the only scene that uses this library, and the other scene I checked doesn't have a mysterious 600MB allocation. And on disk, "everything" is only 18MB at the very most; I have trouble believing that could balloon to 600MB when decompressed. So I was hoping to get some more targeted insight through using debug logging or similar. I'm having trouble finding something that tracks allocations though.

KillHour
Oct 28, 2007


Profiler.BeginSample and Profiler.EndSample are all you need. That will add a line in the profiler for between the two markers and the GC Alloc column will only reflect garbage from inside that code.

KillHour fucked around with this message at 15:21 on Apr 6, 2020

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
Thank you, that did it. It was a sneaky issue -- I recently added a manifest of all of my Resources files, so I can look them up at runtime without knowing their paths. This was replacing some use of System.IO which obviously didn't work in builds. So the actual culprit was a line like
code:
foreach (var path in ResourceFiles.FindFiles("Models/Outfits", ".fbx")) {
which is pretty easy to overlook.

For some reason, generating the manifest produced inordinate amounts of memory churn. I already regenerate the manifest when making a build, and I guess I can add it as an asset postprocessor as well, so there's no need to be doing all this extra work at the beginning of every play.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Nolgthorn posted:

Making games is so difficult. And then nobody appreciates the work that goes into them because they've seen it before.
Another good example of things that seem simple but are a huge pain to actually get right is the UI-gloop. For example, I spent like four hours on Sunday trying to get the math right to resolve this situation:

A thing has a location x,y, a velocity dx,dy, and a maximum acceleration a. There is a target location tx,ty at which the thing wants to stop (i.e. have velocity 0,0)

You can try to resolve this the gamey way by just accelerating towards the place and applying some friction or something and it will eventually resolve, but that sucks. You can *fairly* easily calculate a target velocity from your current location and accelerate towards that velocity each frame, but you'll end up overshooting because of doing math per-frame resulting in small over or underruns every frame (or doing a second round of newton's equations every frame to nullify that).

So what I was aiming to do was actually solve the whole thing with proper math, whereby I calculate the complete path when the situation is encountered, and then I can just play it out with minimal complexity from there. It's fairly easy (ha) in one dimension, the sequence is

1. Use newton/SUVAT to figure out where and when your thing will be when it stops if it max-decelerates.
2. If that distance is between where it is now and the target, consider this as "it can stop negative that distance from where it is now, in negative that much time". Otherwise just keep it.
3. Call those values t1 and p1.
4. SUVAT again to get t2, the time to travel half the distance from p1 to target.
5. Add t1 and t2, that's how long the first half of the path is, where the thing is accelerating at max acceleration. You can now calculate position at any time t less than (t1+t2) using SUVAT from initial pos, initial velocity, and that acceleration.
6. A second path is the other half of the distance from p1 to target, the same amount of time and the same distance as before, but now decelerating.
7. If time t is between (t1+t2) and (t1+t2+t2) you get the position using SUVAT from p1, a zero velocity, and that deceleration.

Now to do it in two dimensions you *can* just do it in one dimension twice, but that way has some flaws:

1. Your 'real' acceleration is higher than the specified max acceleration, because sqrt(a^2+a^2) > a
2. If your target is a long way due 'x' and your velocity is a little bit 'y', the path described is a bump north, then settling back to y=0, then due east the rest of the way. What you really *want* here is the bump north, then a straight gentle diagonal to the target.

I settled on that as good enough for what I was wanting it for because it's just for UI goo, but gently caress why is this stuff so awkward? You'd think it would be something easily found online, but you can barely even find a good one dimensional solution!

(The specific reason for these constraints is UI bits that can change where they want to be while they're still in motion, so a using a common simple curve path could look like poo poo at the transition point, especially in the case where it changes target to a very similar target. Doing it physics-style smooths out those edge cases.)

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
If at all possible, cheat and make the problem easier to solve. I had to solve a similar problem in my game -- I have fleets of ships, where each ship tries to maintain its position relative to the flagship of its fleet, and the fleet as a whole is trying to navigate from one waypoint to another. I solved this as:

* Calculate desired offset o_f from flagship position
* Point ship at waypoint + o_f
* Thrust
* When close to waypoint + o_f, stop thrusting, start turning
* At all times, calculate distance from (flagship + o_f) and if ship is within a short distance (about a ship length or so) just kind of nudge it over. If it's too far then navigate normally.

It works because I don't need highly skilled navigators on these ships (there's a lot of empty space at sea), and because the player usually has better things to do than carefully examine how other ships move. Trying to keep ships on station when they're only able to thrust forwards/backwards and can't turn unless they're moving (a.k.a. "realistic" motion) would be a vastly harder problem.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
Oh lol I just realized I almost *accidentally* got the diagonal in that awkward case, because the system I'm using likes you to put animations on a scale from 0 to 1 with a duration, and I did that with the duration being max(durationXAxis, durationYAxis). I was mapping it back onto the two-axis path, but if I just map that 0-1 animation value to both the axis paths' durations separately, the axis that would be done more quickly gets its animation stretched out over the duration of the other axis's path, leading to a nice soft curve or diagonal.

So the only remaining dodgy bit is that a diagonal acceleration is faster than a straight one, which for UI-goo purposes is 100% not a problem.

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense

roomforthetuna posted:

You can *fairly* easily calculate a target velocity from your current location and accelerate towards that velocity each frame, but you'll end up overshooting because of doing math per-frame resulting in small over or underruns every frame (or doing a second round of newton's equations every frame to nullify that).

Mentioning areas of my code I'm self conscious about? My solution is as follows in Godot.

code:
const MOVEMENT_CLAMP: = 0.15

func move_along_path(agent: KinematicBody) -> void:
	var move_vector: Vector3 = verts[index] - agent.transform.origin
	if move_vector.length() < MOVEMENT_CLAMP:
		index += 1
		in_position = index >= verts.size()
	var linear_velocity: Vector3 = move_vector.normalized() * agent.movement_speed
	agent.move_and_slide(linear_velocity, Vector3(0, 1, 0), true)
So basically, if the move_vector is pretty close then that's good enough and finish up. But you know, if that close enough value is too small then the agent just freaks out overshooting and undershooting the target every frame. Which stands to reason if the game slows down too much and frames are too long then it'll go ahead and overshoot and undershoot.

But like hell anyone in the world has actually figured out how to do this.

After I'm "in position" I just go ahead and set the position to be precise on the next frame.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Nolgthorn posted:

Mentioning areas of my code I'm self conscious about? My solution is as follows in Godot.
Nah, you're only doing fixed speed movement there, the math for that is really easy (even though you're going 3D where I was only doing 2D). You'd just need to bring in the time advance of the last frame to make it precise, which I remember Godot exposes somewhere.

Unless you're relying on move_and_slide to actually shove around obstacles in which case yeah the per-frame faffing and overstep is helping you out, but it's not the same problem at all.

It's when you deal with the third order that brings in acceleration that the math really gets hairy.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Transform it to a polar system (target is r distance away at an angle θ, current speed is v at angle φ), and you can do things exactly the same regardless of how many dimensions you have and will wind up with an orientation-independent result.

mrbotus
Apr 7, 2009

Patron of the Pants
I'm learning python. For practice, I'm working on a text game where you can move from room to room and do stuff. I'm interested in having NPCs move around and give the player little messages as the game waits for the player's input. Are there any resources I can look at to figure out this problem? I'm a newbie programmer, so I was surprised that such a thing seems way more complicated than I thought it would be.

KillHour
Oct 28, 2007


If you're trying to stop something at a predetermined spot, don't apply any forces at all. Just use linear interpolation to set the position directly as a function of time.

Triarii
Jun 14, 2003

KillHour posted:

If you're trying to stop something at a predetermined spot, don't apply any forces at all. Just use linear interpolation to set the position directly as a function of time.

Also if you start the lerp speed at 0 and gradually increase it each frame, you can give an object a believable acceleration/deceleration feel with very little math.

Or if you want perfect physical realism and lots of math, you can use a PID controller. It looks mathematically terrifying (it has "integral" and "derivative" right in the name, and just look at all those scary symbols in the wikipedia article!) but it turns out to be really simple to implement in the context of a game.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Jabor posted:

Transform it to a polar system (target is r distance away at an angle θ, current speed is v at angle φ), and you can do things exactly the same regardless of how many dimensions you have and will wind up with an orientation-independent result.
Yeah, I did consider polar for those benefits but then it seems weird if, for example, you're going east and then get a new target to the west, with polar driving it's going to do a little weird circle rather than just braking and accelerating back the other way. And it's still non-obvious how much you should slow/speed before you're pointing the right way - I think there might be a risk of orbiting the target if you just go for the speed at which, if you were going the right way, you could stop at the target.

KillHour posted:

If you're trying to stop something at a predetermined spot, don't apply any forces at all. Just use linear interpolation to set the position directly as a function of time.
That's how you get the jank from moving north at 10mph to moving east at 10mph, or moving north at 10mph to suddenly not moving because you started a new lerp curve. If you're just going from stopped-at-A to stopped-at-B then yes the simple interpolation works great, but if you can interrupt a path then those options aren't so great.

roomforthetuna fucked around with this message at 05:17 on Apr 8, 2020

xzzy
Mar 5, 2009

nickmeister posted:

I'm learning python. For practice, I'm working on a text game where you can move from room to room and do stuff. I'm interested in having NPCs move around and give the player little messages as the game waits for the player's input. Are there any resources I can look at to figure out this problem? I'm a newbie programmer, so I was surprised that such a thing seems way more complicated than I thought it would be.

The prehistoric way of doing this stuff is with select(), which is a function that has a timer and will listen for some kind of input. If that timer expires it exits and allows the program to do some other stuff (like your NPC chatter). Then once that finishes the program loops and waits in the select() again. As long as you're not calculating primes the user will never notice the delay.

The more modern approach is threads.. which is kind of a big topic but googling "python threads" should get you tons of reading.

Alternatively, look around for a text based python game engine that does it all for you. It'll probably be based on threads but you won't have to think about any of it.

So it is complicated, but it's a well studied problem with a lot of solutions available.

mrbotus
Apr 7, 2009

Patron of the Pants
Great, I'll look into that. I did some googling about python, text-based games, etc. But the only solution I could find on my first search is "...ooh.. I don't know? multithreading? but multithreading is actually bad? uh..."

Ultimately I'd like to create a MUD-like game, but idk how those sorts of games control their npc behaviors. I guess it's easier to do with a server? Again, I don't know, couldn't even figure out how to compile a MUD from the files.

Corla Plankun
May 8, 2007

improve the lives of everyone

nickmeister posted:

Great, I'll look into that. I did some googling about python, text-based games, etc. But the only solution I could find on my first search is "...ooh.. I don't know? multithreading? but multithreading is actually bad? uh..."

Ultimately I'd like to create a MUD-like game, but idk how those sorts of games control their npc behaviors. I guess it's easier to do with a server? Again, I don't know, couldn't even figure out how to compile a MUD from the files.

The easiest way to do this would definitely be to break it into a client and a server, but it is definitely a surprisingly complicated problem to solve (with python) for how easy it is to imagine.

Corla Plankun fucked around with this message at 14:58 on Apr 8, 2020

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe

Triarii posted:

Or if you want perfect physical realism and lots of math, you can use a PID controller. It looks mathematically terrifying (it has "integral" and "derivative" right in the name, and just look at all those scary symbols in the wikipedia article!) but it turns out to be really simple to implement in the context of a game.

The important thing to be aware of with PID controllers is that you need to configure them (by setting 3 multiplier values), and the correct configuration values depend on how they're used. You can get some strange behaviors out of a misconfigured PID controller. Usually for a game you want the controller to be "critically damped", so that it smoothly approaches the final value without overshooting, but you can also get oscillation (where it wobbles back and forth around the final value) and of course you can also set up a controller such that everything shoots off into oblivion.

So yeah, I do recommend them, just be aware that they require some work even after you get the code written. As noted, writing that code is pretty simple.

kaffo
Jun 20, 2017

If it's broken, it's probably my fault

TooMuchAbstraction posted:

The important thing to be aware of with PID controllers is that you need to configure them (by setting 3 multiplier values), and the correct configuration values depend on how they're used. You can get some strange behaviors out of a misconfigured PID controller. Usually for a game you want the controller to be "critically damped", so that it smoothly approaches the final value without overshooting, but you can also get oscillation (where it wobbles back and forth around the final value) and of course you can also set up a controller such that everything shoots off into oblivion.

So yeah, I do recommend them, just be aware that they require some work even after you get the code written. As noted, writing that code is pretty simple.

+1 for PID controllers. You can spend ages tweaking them, but once you put in the right magic numbers some sorcery happens and everything becomes butter. Totally not ashamed to admit I learned a lot about pratical PID in From The Depths.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

roomforthetuna posted:

Another good example of things that seem simple but are a huge pain to actually get right is the UI-gloop. For example, I spent like four hours on Sunday trying to get the math right to resolve this situation:

A thing has a location x,y, a velocity dx,dy, and a maximum acceleration a. There is a target location tx,ty at which the thing wants to stop (i.e. have velocity 0,0)
Ok so basically you want a trajectory x(t), y(t) such that:
x(0) = x, y(0) = y (initial position)
x(tf) = tx, y(tf) = ty (final position)
x'(0) = dx, y'(0) = dy (initial velocity)
x'(tf), y'(tf) = 0 (final velocity)
And at all times: [x''(t)]2 + [y''(t)]2 < a2 (acceleration is less than max acceleration)

The biggest issue here is that there are an infinite number of trajectories that satisfy these conditions (notice how tf is a free parameter). Presumably you want some "simple" trajectory.

I don't have time to work out everything exactly, but the strategy I'd follow is to use a cubic Bezier curve

So the equation for the curve is: B(s) = (1-s)3 P0 + 3(1-s2)s P1 + 3(1-s)s2 P2 + s3 P3
where s goes from 0->1 and (P0, P1, P2, P3) are the control points, all vectors

P0 is the initial point, P3 is the final point. So P0x = x, P0y = y, P3x = tx, and P3y = ty. P1 and P2 aren't set yet, we're going to use the velocties to set them. Also, s goes from 0 to 1, but you want t to go from 0 to tf, so you'll need to set t = s tf. tf also needs to be set. To make things easier I'm going to set q = 1 / tf, so q t = s. The max acceleration will be used to set q. Then x(t) = Bx(q t), y(t) = By(q t) will be our trajectories.

The derivative is:
B'(s) = 3(1-s)2(P1 - P0) + 6(1-s)s (P2 - P1) + 3 s2 (P3 - P2)

So we know that B'(0) = q (dx, dy) (the q appears because q t = s). If we put s=0 into the equation we get 3 (P1 - P0) = q (dx, dy), so P1x = (q/3) dx + x and P1y = (q/3) dy + y.
We also know that B'(1) = 0. That gives us 3 (P3 - P2) = 0, so P2 = P3. So P2x = tx, and P2y = ty.

So now you have all your control points, you just need to set the factor q.
This is where it gets a little tricky. The second derivative is:
B''(s) = 6(1-s)(P2 - 2P1 + P0) + 6s (P3 - 2P2 + P1)
We can simplify B''(s) a little:
B''(s) = 6[(1-s)(P3 - 2P1 + P0) + s (P1 - P3)] = A + B s
where A = 6 (P0 - 2P1 + P3) and B = 6 (-P0 + 3P1 - 2P3)

Now, we want (Bx''(s))2 + (By''(s))2 < q4 a2
So Ax2 + Ay2 + 2s(AxBx + AyBy) + s2 (Bx2 + By2) < q4 a2
Now we're in luck: (Bx2 + By2) > 0, so this quadratic is upwards facing. This means the greatest acceleration will occur at one of the endpoints: s = 0 or s = 1.
Now comes the difficult part: solve for q at s = 0 and s = 1 and pick the lower of the two. Unfortunately, that's pretty difficult because we have a quartic equation (remember: q is buried in P1, and hence A and B are both functions of q). So instead of that mess I'd cheat and use an exponential search to determine q.

Anyway nobody's going to do any of this but I worked it out so I'm posting it :v:

Adbot
ADBOT LOVES YOU

a cyberpunk goose
May 21, 2007

I’m just a simple, humble man, who uses an alpha over time with an AnimationCurve across a start pos and end pos

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply