katt's scripting tests

Hey all,

First, thanks again to all the folks who helped me out in my noob thread. Here’s the results of my second weekend with Unity:

http://ministryofdoom.org/cloud/unity/shiptest2.html

Waypoints FTW! There’re no controls, and it just loops around the “city”. I did it by making two rigid bodies, one that follows the waypoints quite closely (target) and one that follows the target (follower). This gives the illusion of bezier path following without having to do bezier math (which I find myself totally unable to comprehend). (Code package at the bottom of this post.)

I’m using rigid bodies for this, but I’m worried – when I add combat later will this solution hold up? How are other people solving “on rails” combat? I’ve seen a few projects searching through the forums but little code. (I might be searching with the wrong words.) I want it to eventually feel like StarFox 64 and then branch out from there. Currently my idea is to encase the player in an invisible box that follows the waypoints and to somehow dampen thrust when you near the edges of the box (thinking about using raycasting for this), making it look like you’re still thrusting while actually keeping you on track, but I’m having trouble getting it all together. That’s probably next weekend’s trick. :slight_smile:

Also, could someone explain how to slerp between two angles in a way that a three year old could understand it? That’s what I tried first and got nowhere.

And in case it helps anyone, here’s my project. There’s waypoint code, waypoint followers, and a lot of Gizmo drawing:

http://ministryofdoom.org/cloud/unity/shiptest2.zip

here’s how I do it in my current project (a shmup):

  • I have a way points which are just transforms with scripts with variables attached (info like hold time, transfer time, blah blah). All are called PathingNode# (just to help in my mind lay them out and find them

  • I have a transform with a pathingscript on it that points to current node, next node, and lerps, slerps, and burps between them. This is the GamePath. This is also what most objects’s transform parent if I want them to move with my scene.

  • My camera system targets the gamepath object and follows it.

So your pathingnode isn’t a rigidbody, then? You just use linear translation from point to point?

A quick editor thing: I wanted a way to simply extend waypoint paths, so this is a function that creates a new waypoint if none are selected, or extends a current waypoint path. It’s not all that smart but works well for my needs.

class EditorWayPoint extends ScriptableObject
{	
	static function CountWayPoints() : int {
		var count = 0;
		var wparray = FindObjectsOfType(GameObject);
		for (gob in wparray) {
			if (gob.GetComponent("cwWayPoint"))
				count++;
		}
		return count;
	}

	@MenuItem ("katt/WayPoints/Create WayPoint")
	
	static function CreateWayPoint()
	{
		var numPoints = CountWayPoints();
		var ob = GameObject("WayPoint" + numPoints);
		ob.AddComponent("cwWayPoint");
		if (Selection.transforms.length) {
			var wp = Selection.activeGameObject.GetComponent("cwWayPoint");
			if (wp) {
				wp.target = ob;
				ob.transform.position = Selection.activeGameObject.transform.position;
			}
		}
		
		Selection.activeGameObject = ob;
	}

}

Course, the cwWayPoint class is in the file linked above.

This is very cool. Any plans to add some way to vary ship speed? Perhaps have it randomly accelerate or decelerate, or better yet, have it slow as it approaches a waypoint, then accelerate after it turns? How will you handle “banking” the ship?

correct

edit: got bezier line drawing working, script changed.

@BigKahuna:

Varying ship speed is pretty easy… just increase the thrust over time. I was thinking of doing something like that, possibly, by including new thrust speeds inside the waypoints. I figure I can dump a lot of data inside each waypoint and have the Follower ramp up or down to the new speed. I have a similar idea for the up vector (so that I can have the camera rotate along the path a certain way, like into ground holes or straight up without flipping out), but it’s not baked yet.

What is baked, though, is bezier waypoints!

var turnTime : int = 40;
var nextDist : float = 2.5;
static var kLineOfSightCapsuleRadius = 0.25;
var target : GameObject;
var target2 : GameObject;

var size : float = 0.5;
var drawCurve : boolean = true;
var drawHandles : boolean = true;
var drawAsLine : boolean = true;
var curveType : int = 4;		// 4 = cubic bezier, 3 = quadratic
var curveSegments : float = 10.0;	// how smooth the curve should be
var curveDrawType : int = 1;	// 1 = spheres, 2 = line
var curveSphereSize : float = 1.0;

// Draw the waypoint pickable gizmo
function OnDrawGizmos () {
	// Draw lines to the targets if they exist
	ODG_LineToTarget(target);
	ODG_LineToTarget(target2);
	
	Gizmos.color = Color.green;
	Gizmos.DrawWireSphere(transform.position, size);
	Gizmos.DrawIcon (transform.position, "Waypoint.tif");
	if (target) {
		// draw bezier curve
		if (drawCurve) {
			var distance : float = Vector3.Distance(target.transform.position, transform.position);
			var qdist : float = distance / 4.0;
	
			var p1 : Vector3 = transform.TransformPoint(0, 0, qdist);
			var p2 : Vector3 = target.transform.TransformPoint(0, 0, -qdist);

			if (drawHandles) {
				//debug: draw bezier "handles"
				Gizmos.color = Color.red;
				Gizmos.DrawLine(transform.position, p1);
				Gizmos.color = Color.blue;
				Gizmos.DrawLine(p2, target.transform.position);
				Gizmos.color = Color.yellow;
				Gizmos.DrawSphere(p1, curveSphereSize);
				Gizmos.DrawSphere(p2, curveSphereSize);
			}

			// draw the bezier based on the distance and the number of segments
			// does the rounding matter?
			var jumpdist : float = 1.0 / curveSegments;

			// #!FIXME: make it draw lines too
			var lineStart : Vector3 = transform.position;
			var lineEnd : Vector3;
			
			if (!drawAsLine)
				Gizmos.color = Color.green;										
			else
				Gizmos.color = Color.red;

			for (var i : int = 1; i < curveSegments; i++) {
				lineEnd = PointOnBezier4(transform.position, p1, p2, 
									target.transform.position, jumpdist * i);
				if (!drawAsLine)
					Gizmos.DrawSphere(lineEnd, curveSphereSize);
				else {
					Gizmos.DrawLine(lineStart, lineEnd);
					lineStart = lineEnd;
				}
			}
		}
	}
}

function PointOnBezier4(p1 : Vector3, p2 : Vector3, p3 : Vector3, p4 : Vector3, t : float) : Vector3 {
	var q1 : Vector3 = Vector3.Lerp(p1, p2, t);
	var q2 : Vector3 = Vector3.Lerp(p2, p3, t);
	var q3 : Vector3 = Vector3.Lerp(p3, p4, t);
	var r1 : Vector3 = Vector3.Lerp(q1, q2, t);
	var r2 : Vector3 = Vector3.Lerp(q2, q3, t);
	var r3 : Vector3 = Vector3.Lerp(r1, r2, t);

	return r3;
}

// Draw the waypoint lines only when you select one of the waypoints
function OnDrawGizmosSelected () {
	Gizmos.color = Color.yellow;
	Gizmos.DrawWireSphere(transform.position, size);
	Gizmos.DrawIcon (transform.position, "Waypoint.tif");
	
	// draw "bezier" lines
}

function ODG_LineToTarget(ntarget) {
		// for target 1
	if (ntarget) {
		if (Physics.Linecast(transform.position, ntarget.transform.position))
		{
			Gizmos.color = Color.red;
			Gizmos.DrawLine (transform.position, ntarget.transform.position);
		}
		else
		{
			Gizmos.color = Color.green;
			Gizmos.DrawLine (transform.position, ntarget.transform.position);
		}
	}
}

Essentially, a waypoint that has a waypoint for its target will use the Gizmos to draw the path. I’m cheating a lot – I couldn’t think of a simple way to seam together two four-point bezier curve, so I’m kind of making each waypoint like a bezier point with handles. The handles lie along the Z axis. Red points forwards, and blue points backwards.

Hopefully it’ll make sense if you try it out on some empties. Here’s a quick screenshot. Next up: bezier pathing in the Follower!

If you want a way to add WayPoints easily, check out the script above. Hope someone finds the above useful. :slight_smile:

50782--1868--$unityscreensnapz001_896.jpg

New noob question: What’s the quickest way to determine the screen position of an object’s transform? I searched the forum and the docs but I must be using the wrong words because I can’t find anything on it.

Thanks in advance!

Sounds like you want WorldToViewportPoint.

–Eric

Brilliant! Thanks mate. I knew there had to be a function.

Here’s what I came up with. It seems to work… Right now I’ve got an empty parented to the camera so that I can get a working vector. I think Transform.forward works very differently from how I envision it working?

Anyway, is what I have the best way to be doing this – keeping a texture on-screen – or is there a simpler / better way? This script is applied to an in-world empty that then moves a 64x64 GUI texture based on the camera and the camera’s target. The reason I’m using angles is that the objects seem to come up once every 180 degrees.

var innerTexture : GUITexture;
var outerTexture: GUITexture;
var cam : Camera;
var camTarget : GameObject;
var debugGUI : GUIText;

var innerSize : float = 1.0;
var outerSize : float = 1.0;

function Update () {
	
	var theVec : Vector3 = camTarget.transform.position - cam.transform.position;
	var angle = Vector3.Angle(theVec, transform.position - cam.transform.position);
	if (angle < 90) {
		var pos = cam.WorldToScreenPoint(transform.position);		debugGUI.text = "(" + pos.x + ", " + pos.y + ") : Angle " + angle;
		innerTexture.pixelInset = Rect(pos.x - 32, pos.y - 32, 64, 64);
		innerTexture.color.a = 255;
	}

	else {
		debugGUI.text = "Offscreen - Angle is " + angle;
		innerTexture.color.a = 0;
	}
}

Your waypoint system looks awesome! I might just have to try it out. :smile:

I’ve made some progress. A lot of progress, actually, although from this next test you probably won’t think so:

REMOVED LINK

This may not seem to exciting, but it’s using a fully-functional version of my bezier waypoints. (Please ignore the crappiness of the animation – it was just for testing purposes.) Here’s a shot of that:

Essentially the bird is on an infinite loop that’s smoothed out. There’s still a kink or two to work through, but I think it’s working well enough for the next phase of what I want to get going. The waypoints are finally working well enough that I can start on some Really Fun Stuff™.

That’s weird, I just tried your link and it loaded most of the way then I got a “Failed to update webplayer” error? Anyone else?

Damn you’re fast. :slight_smile: It works fine on my end… I can generate a standalone if folks want, but it’s really just a bird flying in a circle.

Your web player was made with the leopard build. Please do not post web players that are made with non-official Unity builds.

I apologize! I didn’t know there’d be a difference – figured the VM or whatever runs things wouldn’t have a problem.

I’ve rebuilt the example using 2.0.0f6. That’s the official release, I hope; a look inside the HTML shows that the user is redirected to grab the beta web player?

Again, sorry. I have the beta in another folder, and I just ran this on my PC, so it should work now.

http://ministryofdoom.org/cloud/unity/mushroom-house.html

bigkahuna, does it work for you now? You’ll probably have to reload the page.

Ahhh… now that works much better!