Jump to content

WIP plugin help - WheelCollider, GUI, GamObject heirarchy


Recommended Posts

Hello!

So I've been working on some wheels in KSP and I can make just about anything I want in terms of size, suspension and grip. However, it gets a bit tedious firing up Unity and making yet another part that's exactly the same as the last, just with different properties of the wheelCollider object that does the physical simulation so I decided to delve into making a plugin to do it in-game.

I've never used Unity before but have some experience writing C for micro controllers. No C# or JS. What a journey!

So I finally figured out how to export as a DLL plugin (took me a while to realise that scripts in Unity don't get exported with the .mu (obvious, really. Duh!), got GUI buttons working, finally managed to access the WheelCollider properties in code, and have something semi functional. Now I'm kinda stuck and would really, really appreciate help from those with a little more experience.

So, here it is:

https://github.com/Lo-FiOrbitalScience/KSPWheelPack

The wheel is semi-finished, mostly untextured and by default set up for light vehicles. At the moment, I've just implemented GUI buttons to increase and decrease the spring value but I'd like to replace this with a slider. You'll notice that if you modify the value for one wheel, it prints the updated spring rate to the log. The status button also works, but simply prints what it's currently set to. This is all well and good, though I've yet to figure out why it takes a few minutes to update in-game - no big deal for the moment. However! If you change another wheel, it continues to print with the value from the last wheel that was changed and this is where I'm confused. I've no doubt in my naivety I've done something really silly in amongst all the class declarations and what-not that I'm only just getting a grasp on. Apologies for the rough code, and I'm sure there are better ways to go about it. Please do tell me! Hopefully I've commented well enough.

If I can get this nailed, I've got a few nice wheel designs to produce, along with adjustable suspension. Ultimately I want to produce a stability controller that will allow modification of spring values for the whole vehicle it's attached to, add anti-roll bars... hell, maybe even automatically fire RCS to stop the thing flipping over when the worst happens! I have a bunch of ideas to make rovers more usable, but all of that is a way off - I've got some serious learning to do!

Any pointers would be very gratefully received :confused:

Link to comment
Share on other sites

You have some code that looks like this:

thiswheelCollider = GameObject.Find("wheelCollider");

This will find ANY GameObject named "wheelCollider" in the scene. If there is more than one with the same name, you can see how there might be trouble. Every instance of your PartModule is (I assume, I don't know how Unity searches internally) finding the exact same wheelCollider and printing its values.

This thread from yesterday will probably be helpful to you.

Link to comment
Share on other sites

Thank you! Missed that, looks like someone has trodden this path already.

I was wondering how it's scoped - makes sense. I'd assumed it would only apply within the object selected.

Link to comment
Share on other sites

If you're calling GameObject.Find(...), then you're calling a static method, and that method doesn't know anything about the part you're looking at. For a method to have "scope" in the sense that you're using the term, then you need to call a method that's on that object, or call a method that takes the object you're looking at as a parameter.

Perhaps you mean to be working with this.part? That's the part that the module you're writing is attached to at runtime.

Link to comment
Share on other sites

Ah, that makes a lot of sense when you put it like that. Cheers, gives me a few more avenues to explore. Then I'll need to take a step back, figure out how to find all the wheelCollider objects on the active craft, rather than the entire scene.

Link to comment
Share on other sites

...figure out how to find all the wheelCollider objects on the active craft, rather than the entire scene.

"this.part.vessel" gives you access to the active craft.

Specifically, it gives you access to the vessel that the part is attached to, where "the part" is the part that your module code is attached to.

Link to comment
Share on other sites

Perfect, this is exactly the kind of thing I need :)

Furiously coding now, I'll keep posting to GIT.

Do you mind if I ask where you get your info from? I found it very hard to find much, other than the Unity docs.

Link to comment
Share on other sites

Glad it's not just me! Actually, what got me going with the KSPField thing to make GUI buttons was having a nose through the mass driver source code :) I'm currently looking at the UI_FloatRange from someone else's code as well.

Link to comment
Share on other sites

Oh yeah, it's definitely not you! I figured out the KSPField annotations from the interstellar mod, and I'm still having some trouble with them...

Hah! Looking again at your and interstellar's code, I figured out the problem: the fields which are annotated with [KSPField] MUST be public fields. This is so that the game can access and set them for you.

So, where I have:


[KSPField(isPersistant = false)] float Efficiency = 0.8f;

it should actually be


[KSPField(isPersistant = false)] public float Efficiency = 0.8f;

Link to comment
Share on other sites

Ahhhh, well spotted! They're private by default is C#. That actually explains a lot if the implications are what I think they are. Cheers, this is really productive!

Link to comment
Share on other sites

You can also look for the component(s) directly, being careful around cases where more than one might exist of course:

var wc = part.FindModelComponent<WheelCollider>();
var wc2 = part.gameObject.GetComponentInChildren<WheelCollider>();

This got it working like a charm in the VAB! Even saves the tweaks.

Still have some delayed update issues in-game. Not actually a big deal, just interested to know what's going on.

Latest source, for future ref is here:

https://github.com/Lo-FiOrbitalScience/KSPWheelPack

Adding other attributes of the WheelCollider as tweakable is now trivial should the need arise. However, on to more interesting things like an anti-roll mechanism!

Link to comment
Share on other sites

I think this is super cool. Would you be open to adding traction and stability control? I think it would be a lot of fun if each wheel could individually adjust its power to avoid slipping (launch control?), or at least have an anti-lock braking system :) If you're open to that, I'd be happy to write some of the code! I think it would make sense to allow the user to enable / disable these systems.

Link to comment
Share on other sites

Cheers! Now it's actually working I'll start a proper WIP release thread.

Hell yes! I have a few things on my list:

1) Make the plugin an extension to ModuleWheel. This will mean it applies to all wheels by default, rather than having to .cfg edit the custom module name in to call the plugin. I think this can be done with an override, though I'm not sure.

2) Stability control. Yep, absolutely. There is example code in the Unity docs, so it's a case of getting the code to find all wheels on a craft, pair them up by looking at their position and applying it appropriately. Another tweakable here.

3) Traction control could be quite cool. Have to look into how to interrogate whether a wheel is slipping, but there is some example code around for modifying torque I think.

4) Anti-flip. Would be seriously cool be be able to fire RCS and use SAS appropriately if more than half the wheels come off the ground. Need to be really careful as this could lead to some stability problems at high speed in itself!

5) There is NOOOOOO rule five

6) Definitely tweakable buttons for all of this, though attachable to action groups.

7) This is a hard one. Smooth out the wheels steering. Does my head in the way they just flip left to right instantaneously. The example car games implement it so much better (and again, working code examples)! Also, make wheels steer in proportion to how far they are from the center of the vehicle.

Be great if you're up for it :D

Link to comment
Share on other sites

3) Traction control could be quite cool. Have to look into how to interrogate whether a wheel is slipping, but there is some example code around for modifying torque I think.

I think you may be able to look at wheel.forwardFriction, and looking at the WheelFrictionCurve to determine where on the curve the current friction lies. Then, you are effectively determining "is slipping", and could reduce torque on that wheel accordingly.

4) Anti-flip. Would be seriously cool be be able to fire RCS and use SAS appropriately if more than half the wheels come off the ground. Need to be really careful as this could lead to some stability problems at high speed in itself!

I'm curious if it's possible to apply steering to align the vessel with the surface normal and direction of travel (align the vessel to be "flat" on the ground and pointing in the direction of travel). That would help a lot for those times when you do a jump off a ridge.

Link to comment
Share on other sites

I think you may be able to look at wheel.forwardFriction, and looking at the WheelFrictionCurve to determine where on the curve the current friction lies. Then, you are effectively determining "is slipping", and could reduce torque on that wheel accordingly.

That'll do it.

I'm curious if it's possible to apply steering to align the vessel with the surface normal and direction of travel (align the vessel to be "flat" on the ground and pointing in the direction of travel). That would help a lot for those times when you do a jump off a ridge.

Hmmm, that's an interesting point. You can use raycasters to judge distance I believe - this is essentially how the wheelcollider functions. (I've clearly read too many Unity docs!)

The method would be something like:


Init
{
Find the length of the vessel
Create a raycaster at each end
}

Update
{
Monitor wheels to check if they are all off the ground. //wheel.hit, I believe.
If so, apply available RCS and SAS to rotate the vehicle so the raycaster values match. //This is probably the hardest part to code if you're going to prevent oscillations and over-correction!!
}

Direction of travel must be accessible as a vector somewhere, I'm sure. Check in the correct plane, correct accordingly. Looks like a whole heap of fun!

Link to comment
Share on other sites

1) Make the plugin an extension to ModuleWheel. This will mean it applies to all wheels by default, rather than having to .cfg edit the custom module name in to call the plugin. I think this can be done with an override, though I'm not sure.

In reading another thread, I found the solution to this: http://forum.kerbalspaceprogram.com/threads/79603-0-2-35-CELSS-Greenhouse-%28TAC-Life-Support-Add-On-Version-0-1-beta%29?p=1154288&viewfull=1#post1154288

Using module manager, you can add modules to existing parts. In that thread, look at the [spoiler: Config]

Link to comment
Share on other sites

Hey, you definitely want to check out this thread in the Unity forums. It is common for people making cars in Unity to find that they are really unstable, flipping even at pretty low speeds. Traditionally, they use very unrealistic workarounds, like making the center of mass at (or below!) the floor of the vehicle, exaggerated aerodynamic downforce, and even applying torque directly to the car to assist in turning. That thread shows how to make a realistically stable car in Unity, but the information is very useful in KSP too. It says that the unstability is mainly because of 2 things:

- The default friction values for WheelColliders in Unity is infinite in practice: The maximal force is 20 KN! That is half the thrust of an engine of this airplane! The stock black wheel has those same values, but the yellow ones don't.

- No anti-roll bars. They are absolutely essential for a (non-arcade) vehicle, and that is why KSP vehicles flip so easily even at low speeds. I suggest you implement it before stability control, as it is easier and more useful. The Unity thread i linked shows how to code it, applying forces in the car to simulate the anti-roll bars (as WheelColliders don't support them).

But you need to know how much the suspension is currently compressed, and there is not a variable in WheelCollider for you to simply read. The thread in the Unity forums shows how to know that, but there is no explanation, so it is unintuitive for someone without experience with Unity API. I will explain it here:

First note that the wheel transform position is not affected by suspension, the virtual wheel does all the movement. Actually i think the transform does rotate for steering in KSP, but that is unrelated.

GetGroundHit().point gives you the position of the point of contact with the ground. So, you can see the distance from it and the wheel transform, that way getting the current suspension travel.

The problem is that GetGroundhit.point is in world coordinates, not local. Fortunately there is a function that you can call on a transform, that inputs a world coordinate point and outputs the same point but in local space of the transform. That function is InverseTransformPoint(Vector3 position). Call it on the transform of wheel, using GetGroundHit().point as input, and it will return the point of contact with the ground, in local space (lets call that "hitPoint"). Then, since the origin of the coordinate system (the 'point zero') will be right at the wheel transform, you just see the y of hitPoint to know the distance from the wheel transform. But this value will be negative, so you invert the signal:

-hitPoint.y //The current suspension travel, in meters

However, this is the distance from the wheel center in fully compressed state, to the wheel bottom in fully extended state. You need to subtract the wheel radius for it to be correct:

-hitPoint.y - myWheel.radius //This is the current suspension travel distance, in meters

Finally, to get a 0-1 value representing how much the suspension is compressed:

(-hitPoint.y - myWheel.radius) / myWheel.suspensionDistance //0 is fully compressed and 1 is fully extended

Remember that hitPoint = myWheel.transform.InverseTransformPoint(myWheel.GetGroundHit().point) .

For the rest, check the thread.

As an unrelated note, did you notice that the spring force of the stock wheels is impressively low (just a few newtons)? I think this means there is no suspension in practice, making the roll problem even worse. I am going to make some tests to see if that is actually true.

Link to comment
Share on other sites

You legend! That thread is an absolute gem, isn't it.

Hey, you definitely want to check out this thread in the Unity forums. It is common for people making cars in Unity to find that they are really unstable, flipping even at pretty low speeds. Traditionally, they use very unrealistic workarounds, like making the center of mass at (or below!) the floor of the vehicle, exaggerated aerodynamic downforce, and even applying torque directly to the car to assist in turning. That thread shows how to make a realistically stable car in Unity, but the information is very useful in KSP too. It says that the unstability is mainly because of 2 things:

- The default friction values for WheelColliders in Unity is infinite in practice: The maximal force is 20 KN! That is half the thrust of an engine of this airplane! The stock black wheel has those same values, but the yellow ones don't.

The defaults are crazy, aren't they. Took me a while messing around to get something that works well.

- No anti-roll bars. They are absolutely essential for a (non-arcade) vehicle, and that is why KSP vehicles flip so easily even at low speeds. I suggest you implement it before stability control, as it is easier and more useful. The Unity thread i linked shows how to code it, applying forces in the car to simulate the anti-roll bars (as WheelColliders don't support them).

don't.

Top of my list to implement!

But you need to know how much the suspension is currently compressed, and there is not a variable in WheelCollider for you to simply read. The thread in the Unity forums shows how to know that, but there is no explanation, so it is unintuitive for someone without experience with Unity API. I will explain it here:

First note that the wheel transform position is not affected by suspension, the virtual wheel does all the movement. Actually i think the transform does rotate for steering in KSP, but that is unrelated.

GetGroundHit().point gives you the position of the point of contact with the ground. So, you can see the distance from it and the wheel transform, that way getting the current suspension travel.

The problem is that GetGroundhit.point is in world coordinates, not local. Fortunately there is a function that you can call on a transform, that inputs a world coordinate point and outputs the same point but in local space of the transform. That function is InverseTransformPoint(Vector3 position). Call it on the transform of wheel, using GetGroundHit().point as input, and it will return the point of contact with the ground, in local space (lets call that "hitPoint"). Then, since the origin of the coordinate system (the 'point zero') will be right at the wheel transform, you just see the y of hitPoint to know the distance from the wheel transform. But this value will be negative, so you invert the signal:

-hitPoint.y //The current suspension travel, in meters

However, this is the distance from the wheel center in fully compressed state, to the wheel bottom in fully extended state. You need to subtract the wheel radius for it to be correct:

-hitPoint.y - myWheel.radius //This is the current suspension travel distance, in meters

Finally, to get a 0-1 value representing how much the suspension is compressed:

(-hitPoint.y - myWheel.radius) / myWheel.suspensionDistance //0 is fully compressed and 1 is fully extended

Remember that hitPoint = myWheel.transform.InverseTransformPoint(myWheel.GetGroundHit().point) .

don't.

That's seriously helpful. The part I'm stuck on is how to scan the vessel for wheels, assign them each a unique identifier and pair them up based on their position in the Z plane and +/- value in the X plane. I also want to use this info to implement steering based on how far the wheels are between the foremost or rearmost set of wheels from the CoM so they will steer an appropriate amount on vehicles with more than two sets of wheels. Getting this info set up seems to be the cornerstone of doing anything really useful. Which begs a sub question... is it better to have a part with the module assigned that does all thisrather than assigning the module to every wheel.? Call it a Rover Stability Module, a little like the MechJeb AR202.

For the rest, check the thread.

As an unrelated note, did you notice that the spring force of the stock wheels is impressively low (just a few newtons)? I think this means there is no suspension in practice, making the roll problem even worse. I am going to make some tests to see if that is actually true.

Yes, that puzzled me. Though real springs are usually rated in kg/mm deflection (I've worked in motorsport on and off) and nowhere in the docs can I find what the Unity rate actually represents. In practice, usable values do seems very, very low.

Thanks for the pointers, be happy to add you to the GitHub project?

Edited by lo-fi
Link to comment
Share on other sites

In reading another thread, I found the solution to this: http://forum.kerbalspaceprogram.com/threads/79603-0-2-35-CELSS-Greenhouse-%28TAC-Life-Support-Add-On-Version-0-1-beta%29?p=1154288&viewfull=1#post1154288

Using module manager, you can add modules to existing parts. In that thread, look at the [spoiler: Config]

Thanks, that might come in rather handy

Link to comment
Share on other sites

Well yes, but more so you can jump in and contribute if you feel like it :)

By the way, do you want a custom model for your engine mod? If you've got any ideas how you'd like it to look I'd be happy to knock something up when I have a few minutes free

Link to comment
Share on other sites

Well yes, but more so you can jump in and contribute if you feel like it :)

Yes :). I made a GitHub account to post my mods, but when i saw all that stuff about git, i decided to put them on Dropbox, as i was just looking for a place for others to download it.

Any progress on fixing the delay bug? Or just finding out why it happens? It makes no sense to me. Have you tested if it happens with other variables, like wheel radius?

By the way, do you want a custom model for your engine mod? If you've got any ideas how you'd like it to look I'd be happy to knock something up when I have a few minutes free

That would be nice, considering that the only thing i know to do is primitive shapes and retextures of stock models. But right now i just want to have fun playing KSP, as since 23.5 came out, i have not touched an asteroid yet, not even the ARM parts, so i decided to capture one that is on a escape trajectory on Kerbin and make a construction and refueling base on it :).

Edited by ThermalShark
Link
Link to comment
Share on other sites

Cool, what's your GitHub handle?

No, not really looked into the delay bug, still thinking on it. Noticed something about how the tweaked value is saved in the save file, but not taken it any further yet. Just have a feeling it's going to be a tricky one :/ All works perfectly when you set in the VAB/SPH and I've not tried messing with other properties. Next thing is to add some code to modify the damper as a proportion of the spring value as I've found the damper wants to be spring / 7.5 for nice behaviour. I'll compile a test version of the DLL for you to enable in-flight tweaks so you can see for yourself. Be interested to see what you make of my wheels as well.

I know what you mean about not getting to play the game! I only got round to getting to an asteroid so I could see what it looked like when I replaced the asteroid model with a kraken I knocked up :D Just thought it would be a laugh, then it got me looking at other stuff and I haven't stopped messing about with modding stuff since... Damn that kraken. Cool idea about the refuelling base.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...