Player can grab ledge, hoists up, move on non-horizontal one

Post tutorials on how to do certain tasks within game or engine code here.
daemonicky
Posts: 185
Joined: Wed Apr 13, 2011 1:34 pm

Player can grab ledge, hoists up, move on non-horizontal one

Post by daemonicky »

(Repost to correct section. Added picture.)

It works by making traceline test of two lines http://i51.tinypic.com/2ywuyz8.jpg . If upper line is unblocked and lower block we are on the ledge.

0. there is a test map and wad :
http://www.mediafire.com/?4bddbl2cdg1g93l
http://www.mediafire.com/?f8i2hxk7k5h9mff

1. First version.
http://pastebin.com/RLyY557h

How it works?
Player detects if there is a ledge around him and grabs onto it. Ledge is detected by testing 2 points near each other - if lower point is inside wall and upper not, then we have ledge. Grabbing is done by simple state machine - if a ledge is found, flag is set, stop moving in z direction (set velocity_z to 0), remember z and reset to that z every time you are on a ledge (flag is set).
Ledge is detected by doing this test around player so he can grab corners, holes in wall and so on ...

First I thought about spawning some entities which would keep player near them. Like springs. But I do not have such experience with Quake C yet.

2. Ability ty hoist up the ledge.
http://pastebin.com/PBgU1asW

Use (for example) :

void() PlayerPostThink =
{
if (PlayerDoGrab(PLAYER_RADIUS))
{
if button to hoist up
PlayerClimb();


4. Ability to move on non horizontal ledge :
http://pastebin.com/8uAUU3nn

Should work.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Pretty neat tutorial. I wondered how that could possibly work.

Just because I don't trust 3rd parties sites:

Code: Select all

// by daemonicky
// comments are translated
// I may have put some errors while dumping this code
// I apologize for them


void() PlayerPostThink =
{
	if (PlayerDoGrab(PLAYER_RADIUS))
        {
          // player grabbed onto ledge or something
...

//
// declarations and globals
// 

float GRAB_EYE_UP = 10; // how much from origin eye is
float GRAB_HAND_UP = 15; // how much from origin hand is
float PLAYER_LEGS = 24;
float PLAYER_RADIUS = 32;
float PLAYER_HEIGHT = 56;//24 /* PLAYER_LEGS */+ 32;

float grab_can;
float grab_z;

float(vector _origin, float _radius, vector _angles) PlayerCanGrabOne;
float(vector _origin, float _radius, float _n) PlayerCanGrabAround;


....


float(float _radius/*hack*/) PlayerDoGrab =
{
        // the grabbing itself
	if (grab_can)
	{
                // there is a chance it is safe and 
                // does not causes problems
                // i do not know for sure
		if (TRUE)
		{
			
			local vector SafeOrigin;
			SafeOrigin = self.origin;
			SafeOrigin_z = grab_z;
			setorigin(self,SafeOrigin);
		}
		else
		{
                // unsafe
			self.origin_z = grab_z;
		}
		self.velocity_z = 0; // gravitation is always applied so do this
		// TODO: make it less rigid
		self.velocity = self.velocity * 0.5;
	}

        // always test
	if (PlayerCanGrab(_radius/*hack*/))
	{
		// for first time- turned on
		if (!grab_can)
		{
			// it was set
			grab_can = TRUE;
			// remember height
			grab_z = self.origin_z;
			PlayerStop();

			// possible alternative : self.movetype = MOVETYPE_FLY;
		}
	}
	else
	{
		grab_can = FALSE;
	}	
	return grab_can;
}

float(float _radius/*hack*/) PlayerCanGrab =
{
	return PlayerCanGrabAround(self.origin, _radius/*hack*/,  4 * 4);
        // was threre, but not so cool
	// return PlayerCanGrabOne(self.origin, _radius/*hack*/, self.angles);
};



float(vector _origin, float _radius, vector _angles) PlayerCanGrabOne =
{
	local vector Eye;
	local vector Hand;

	// remove pitch
	/* v_forward = */ makevectors('0 1 0' * _angles_y + '0 0 1' * _angles_z); // 
	Eye = _origin + v_forward*_radius + v_up *GRAB_EYE_UP; 
	Hand = Eye;
	Hand_z += GRAB_HAND_UP;
	
	if (FALSE) // debug
	{
		particle(Hand, '0 0 0', 1, 10);
		particle(Eye, '0 0 0', 2, 10);		
	}

	// eye is inside wall
	traceline(_origin, Eye, TRUE, self);
	if (trace_fraction == 1.0) //
		return FALSE; 

	// hand is free
	traceline(_origin, Hand, TRUE, self);
	if (trace_fraction != 1.0) {
		return FALSE; 
	}
	//bprint(" grab");
	return TRUE;
}

float(vector _origin, float _radius, float _n) PlayerCanGrabAround =
{
	local vector v = '0 0 0';
	while(v_y < 360)
	{
		if (PlayerCanGrabOne(_origin, _radius, v))
			return TRUE;
		v_y += 360/_n;
	}
	return FALSE;
}
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
behind_you
Posts: 237
Joined: Sat Feb 05, 2011 6:57 am
Location: Tripoli, Libya

Post by behind_you »

it seems like a good idea. im guessing it would look best with 3rd person view + animations.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Embedding other pieces that I missed:

Code: Select all

// by deamonicky
// uses code from http://pastebin.com/RLyY557h
//

// idea is to create enty similar to quake at position where one wants to pull up
// then drop it to floor
// if it is successful then player can drop here too
void() PlayerClimb =
{
	local vector ClimbedOrigin;
	local vector SavedOrigin;
/*
	makevectors(self.angles);
	v_forward = normalize(v_forward);
	v_up = normalize(v_up);
	bprint(vtos(v_up));
	bprint(" ");
	bprint(vtos(v_forward));
*/
	//ClimbedOrigin = self.origin + v_forward * (PLAYER_RADIUS/2) + v_up * (PLAYER_LEGS + GRAB_HAND_UP);

	
	makevectors(self.angles);
	ClimbedOrigin = self.origin + v_forward * (PLAYER_RADIUS*0.5) + v_up * (PLAYER_LEGS + GRAB_HAND_UP);
	bprint(vtos(ClimbedOrigin));
	particle(ClimbedOrigin, '0 0 0',128, 5);
	/*
                not working !!!
		ClimbedOrigin_y += PLAYER_RADIUS/2;
		ClimbedOrigin_z += GRAB_UP;
		ClimbedOrigin_z += PLAYER_LEGS;
		ClimbedOrigin_z += 2; // error
	*/
	// particle(ClimbedOrigin, '0 0 0',128, 5);
	SavedOrigin = self.origin; /* FIXME: add some error deltas */
	setorigin(self, ClimbedOrigin);
	if (!droptofloor()) // can drop here ?
	{
		setorigin(self, SavedOrigin);
		bprint("hups!\n");
		ClimbedOrigin_z += GRAB_EYE_UP;
		setorigin(self, ClimbedOrigin);
		if (!droptofloor())
		{
			setorigin(self, SavedOrigin);
			bprint("hups!\n"); // could not do that
		}
	}
	else
	{
		return;
	}
};

Code: Select all

// by daemonicky
if (grab_can)
...
	// handle slopes
	nudge_up = '0 0 0';
	while (nudge_up_z < 5)
	{
		if (PlayerCanGrabAround(self.origin + nudge_up, _radius/*hack*/,  4 * 4))
		{
			setorigin(self, self.origin+nudge_up);
			grab_z += nudge_up_z;
			break;
		}
		nudge_up_z += 0.6;//0.5;
	}
	bprint(vtos(nudge_up));
	bprint("\n");

	if (PlayerCanGrab(_radius/*hack*/))
...
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
daemonicky
Posts: 185
Joined: Wed Apr 13, 2011 1:34 pm

Post by daemonicky »

I think you can simulate hands by doing tracelines. So rock-climbing would be possible. And boxing probably too ... because tracelines would map to bones of real hands.

I wondered whether I can achieve doing something like combat in Dark Messiah Of Might And Magic http://www.youtube.com/watch?v=caB1jodPQPQ with tracelines. Quake axe is done just by one traceline.

...
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Post by taniwha »

This is great. I've been considering doing a tomb raider like mod for a while (especially after playing Wander and the Colossus and ICO on the PS2). I was thinking that lots of fancy entities would be needed.

That said, there are a couple of problems in your design and code as presented. NOTE: this is only by inspection. I have not yet tried to use your code (though I plan on doing so).

First, the problem in the code itself: you call PlayerStop, but there is no such function in either your code or the quake code. Did you forget this, or are you using modified progs?

Now the design problems, of which there are two (though really just in the code):
  1. Both the Eye and Hand tracelines are from the origin, and thus neither are horizontal. Worse, they are not parallel to each other. This can be solved by having an Eye_origin and a Hand_origin, both offset vertically from the origin, and then the respective tracelines are taken from these origins.
  2. You don't check how high the ledge actually is, so I expect inconsistent results when trying to grab a ledge. This can be done by doing a third traceline: from the Eye endpoint to the Hand endpoint (the original endpoint, not the result of the traceline). This will give the needed information about the plane of the ledge, allowing the player to always stop at the same height relative to the ledge.
The concept is great. I'll see what I can do with it.

[edit] PS: I'm not sure how to apply your movement block.
Leave others their otherness.
http://quakeforge.net/
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Post by taniwha »

Ok, I got your code working (minus the slope movement). Neat stuff, though it has some... places needing tweaking.
  • My suggestion for the third traceline might make slope traversal more usable (I'll check this out later).
  • Not grabbing when FL_ONGROUND is set might be a good idea. Currently, walking beside a grabable ledge causes the player to go into grab mode and thus slow to a crawl (ie, forces the player to use the ledge rather than walking normally).
  • Another idea, possibly as well as the FL_ONGROUND check, would be to require a "grab" button.
Overall, I like your patch.

PS: I just tested adding a check for FL_ONGROUND (I put it in PlayerPostThink), and it does make the grabbing less obnoxious. A way to let go would be nice, too, but that seems to be suitable for the PostThink code block.
Leave others their otherness.
http://quakeforge.net/
daemonicky
Posts: 185
Joined: Wed Apr 13, 2011 1:34 pm

Post by daemonicky »

taniwha wrote:This is great. I've been considering doing a tomb raider like mod for a while (especially after playing Wander and the Colossus and ICO on the PS2). I was thinking that lots of fancy entities would be needed.
Cool. I'd like to see that. :)
taniwha wrote: First, the problem in the code itself: you call PlayerStop
Sorry, I forget about it.

Code: Select all

void() PlayerStop =
{
	self.velocity = '0 0 0';
}
taniwha wrote: [*]Both the Eye and Hand tracelines are from the origin, and thus neither are horizontal. Worse, they are not parallel to each other. This can be solved by having an Eye_origin and a Hand_origin, both offset vertically from the origin, and then the respective tracelines are taken from these origins.
Totally, but it works even if they are not that way, but I see the problem with this.
taniwha wrote: [*]You don't check how high the ledge actually is, so I expect inconsistent results when trying to grab a ledge. This can be done by doing a third traceline: from the Eye endpoint to the Hand endpoint (the original endpoint, not the result of the traceline). This will give the needed information about the plane of the ledge, allowing the player to always stop at the same height relative to the ledge.
I dont need to check how hight it is. I was thinking: it is somewhere between two tracelines (upper detecting empty space, lower detecting solid space) ... yes, there is an error but it worked when I played it.

Yes. You can get it that way. :) But You might have problem http://img7.imagebanana.com/img/vdm0gzu ... roblem.png . I would probably shoot upwards from hand (lower) position of collision with wall http://img7.imagebanana.com/img/nlsprg4 ... lution.png .
taniwha wrote:[edit] PS: I'm not sure how to apply your movement block.

If you mean PlayerDoGrab then you put it inside the posthink or prethink.
If you mean "Ability to move on non horizontal ledge" then it is a hack which shoots as many tracelines so it can grab ledge which is not horizontal because if he moves http://img7.imagebanana.com/img/ssdmw3n ... moving.png .

I now can see the code is a mess and apologize for that.
Think, touch, movetype, solid, traceline ...
daemonicky
Posts: 185
Joined: Wed Apr 13, 2011 1:34 pm

Post by daemonicky »

taniwha wrote:FL_ONGROUND is set might be a good idea. Currently, walking beside a grabable ledge causes the player to go into grab mode and thus slow to a crawl (ie, forces the player to use the ledge rather than walking normally).
... grab button.
Thanks. Good idea. Either is solution. :)

Lettin go would probably be in having some variable which would toggle behaviour or have variable which defines lenght of tracelines (and set it to 0 :) ; it should most likely work the first time).

Tomb Raider levels

When You are making Tomb Raider clone check out TRosettaStone http://www.tnlc.com/eep/tr/TRosettaStone.html and TrueView http://www.tnlc.com/eep/tr/utils.html . TrueView has source code and You can extract Tomb Raider levels into Quake maps http://www.gamers.org/dEngine/quake/QDP ... html#2.1.2 ...

I know how to do it theoretically not practically. I have not looked at the code of TreuView for soem time but there is funciton to draw all polygons of room ... you need to make a brush out of each of these polygons ...
There is how I imagine You do it http://img7.imagebanana.com/img/3gnub2h ... apfile.png . I planned doing it but then let it be, because I needed Tomb Raider levels no more :) ...
Think, touch, movetype, solid, traceline ...
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Post by taniwha »

First, I have to say that when I did try out your code, I was very impressed. Contrary to my expectations, it worked quite well and seemed fairly consistent. The FL_ONGROUND and grab-key suggestions came from actually trying things.

I couldn't see your pics (1x1 gifs), but I think I know to what problem you are referring: very thin ledges: quite right. I hadn't thought of that. While your idea of shooting up from the lower position (collision point) sounds good, it won't work in quake as the engine never blocks a trace going from solid to non-solid (it doesn't even get "all solid" right all the time).

However, obtaining the (lower) collision point, going half a quake unit beyond it, and doing a traceline from the upper point (same distance as the collision point plus a bit) should work: anything smaller than 1 quake unit is either a wedge or normally impossible.

[edit]I just realized that climbing slopes might be interesting. but making good use of the plane information returned from traceline might help.

I'll see if I can get some hacking done this weekend.
Leave others their otherness.
http://quakeforge.net/
daemonicky
Posts: 185
Joined: Wed Apr 13, 2011 1:34 pm

Post by daemonicky »

You dont see pics on imagebanana? There is image shack version http://img196.imageshack.us/img196/8255 ... mapfil.png .

I am not sure what You mean, I would need a picture, but You work on it and it seems it works for You so You are most likely right. :) I am glad it worked for You.

Post Your progress. I am interested in how You are remaking Tomb Raider. In theory You can even emulate Tomb Raider Scripting Engine :-D because it is also written in TRossetaStone document.
Think, touch, movetype, solid, traceline ...
behind_you
Posts: 237
Joined: Sat Feb 05, 2011 6:57 am
Location: Tripoli, Libya

Re: Player can grab ledge, hoists up, move on non-horizontal

Post by behind_you »

daemonicky wrote:It works by making traceline test of two lines. If upper line is unblocked and lower block we are on the ledge
can you explain what you mean by "upped line is unblocked"? do you mean if the upper line travels farther than the bottom?
behind_you
Posts: 237
Joined: Sat Feb 05, 2011 6:57 am
Location: Tripoli, Libya

Re: Player can grab ledge, hoists up, move on non-horizontal

Post by behind_you »

daemonicky wrote:It works by making traceline test of two lines. If upper line is unblocked and lower block we are on the ledge
can you explain what you mean by "upped line is unblocked"? do you mean if the upper line travels farther than the bottom?
daemonicky
Posts: 185
Joined: Wed Apr 13, 2011 1:34 pm

Re: Player can grab ledge, hoists up, move on non-horizontal

Post by daemonicky »

behind_you wrote:
daemonicky wrote:It works by making traceline test of two lines. If upper line is unblocked and lower block we are on the ledge
can you explain what you mean by "upped line is unblocked"? do you mean if the upper line travels farther than the bottom?
If traceline_fraction = 1.0.

Look at those two lines with circles at http://i51.tinypic.com/2ywuyz8.jpg , when there is a ledge the upper line will have traceline_fraction = 1.0 a and the lower one will have traceline fraction < 1.0.
Think, touch, movetype, solid, traceline ...
behind_you
Posts: 237
Joined: Sat Feb 05, 2011 6:57 am
Location: Tripoli, Libya

Re: Player can grab ledge, hoists up, move on non-horizontal

Post by behind_you »

daemonicky wrote:If traceline_fraction = 1.0.
I see. So the lines travel a certain distance, the bottom line should hit something while the top hits nothing. then you can climb.


There's a problem with this:

Image

You can see that if you are standing in front of a slanted wall, and you do this, it will think there's a ledge when there is not.

Might I suggest after your ledge check, you do a traceline downwards from the second traceline. When this new traceline hits the brush, make it see if trace_plane_normal >= 0.8. Not a perfect way of doing it but it does the job.

Good stuff, though
Post Reply