while loop trouble ?

Discuss programming in the QuakeC language.
Post Reply
sniperz227
Posts: 112
Joined: Sat Apr 09, 2011 3:19 am

while loop trouble ?

Post by sniperz227 »

hey i've been having a lot of trouble with while loops in qc. for some reason everytime i make a while loop and run it crashes in game? here's some of my code that crashes when i call the function in game.

Code: Select all

/*
=====================================
=============Sprint Function=========
=====================================
*/

void() sprinting =
{
	local .float sprint_time; // float to keep track of sprint time
	stuffcmd(self,"cl_forwardspeed 650"); // sprint speed
	while ("cl_forwardspeed 650") // while the player is sprinting
	{
		self.sprint_time = time + 1; // keep going up by one second
	}
	if ("cl_forwardspeed 200")// if player is not sprinting and in normal speed
	{
		self.sprint_time = 0; // sprint_time is reset to 0 so that when it is called again it is not set to the previous sprint_time
	}
	while (self.sprint_time < 0) // while sprint time is greater than 0 aka player is sprinting
	{
		self.energy = self.energy - 5; // take 5 out of self.energy
	}
	
	if (self.energy == 0) // if theres no energy
	{
		centerprint(self,"You Have No More Energy left to sprint");
	}

}
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: while loop trouble ?

Post by Baker »

Comments:

1. if ("cl_forwardspeed 200") <----- you can't do that. That is a string like "my name is bob" and you cannot evaluate it. Even worse, the QuakeC compiler might try too.
2. cl_forwardspeed is a client cvar, the server has no idea of the value
3. cl_forwardspeed is the speed the player wants to move if moving. That does not mean they are moving.

What you probably want is self.velocity, the speed component broken down into self.velocity_x, self.velocity_y, self.velocity_z

In QuakeC, I'm not 100% sure how you convert that to a true speed. For QuakeC I think it might be the vlen function.

Code: Select all

local float playerspeed;

playerspeed = vlen(self.velocity);
And that player speed would then be the speed they are moving. By the way, that does not mean they want to move that speed. They could be falling.

Look at client.qc for more infos ...

http://inside3d.com/browse.php?show=client.qc

There is a lot more wrong with your example. Like the speed the player is moving is NEVER going to change in that loop. QuakeC thinks about a player's speed once per frame, it does not change during the course of a single function in QuakeC.
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 ..
sniperz227
Posts: 112
Joined: Sat Apr 09, 2011 3:19 am

Re: while loop trouble ?

Post by sniperz227 »

oh well what i have an impulse to set the speed back to normal and one to sprint thats why i wanted to check if the player is sprinting or not cuz i cant let the player sprint forever :P
DukeInstinct
Posts: 20
Joined: Sat Jul 10, 2010 11:20 pm
Location: DukeLand
Contact:

Re: while loop trouble ?

Post by DukeInstinct »

Ya even if you could do "while ("cl_forwardspeed 650")" that would be an infinite loop which would kill the game. Idk how that even got through compilation without error. All I can guess is it thinks you want to compare if the value of the string is non-zero. Which would also be an infinite loop. The design of this code is very flawed, to be honest. This function wouldn't return until the player stopped sprinting(if at all), meaning nothing else would get done during that time.

I think what you should do is add an entity field (but preferably a flag) that is set to true once the sprint button is pressed and then just change the cvar for cl_forwardspeed once that happens. Set up another entity field that indicates the player's energy. When the sprint button isn't pressed anymore or the energy of the player is depleted, set the field to false and return the cl_fowardspeed cvar to it's normal value.

Maybe something like this:

Code: Select all

.float isSprinting;
.float sprintTime;
.float oldTime;

// call this when the sprint button is pressed down
void() sprint_start =
{
	if (sprintTime > 0) // check if energy isn't already depleted
	{
		isSprinting = true;
		sprintTime = sprintTime + time;
		stuffcmd(self,"cl_forwardspeed 650");
	}
}

// call this when the sprint button is released or energy is depleted
void() sprint_stop =
{
	isSprinting = false;
	sprintTime = sprintTime - time;
	stuffcmd(self, "cl_fowardspeed 200");
}

// call this function every frame
void() sprint_update =
{
	if (isSprinting)
	{
		if (time >= sprintTime)
			sprint_stop();
	}
	else if (sprintTime < 5) // recharge sprint energy
	{
		sprintTime += time - oldTime; // increment by time between last frame and current frame. 
							     // 1 second of sprinting per 1 second of recharging
		if (sprintTime > 5) // force maximum of 5 seconds
			sprintTime = 5;
	}

        oldTime = time;
}
EDIT: This code doesn't account for if you hold the button down but don't actually try to move. lol
You should also add "&& (velocity_x > 0 || velocity_y > 0)" to "if (isSprinting)" in the function "sprint_update". This makes sure the player is moving forward/backwards or is strafing, and isn't in mid-air.

Also I wanted to point out that you shouldn't do things like:

Code: Select all

while (self.sprint_time < 0) // while sprint time is greater than 0 aka player is sprinting
{
      self.energy = self.energy - 5; // take 5 out of self.energy
}
This just instantly depletes the player's energy and also puts it far into the negatives depending on how fast the condition "self.sprint_time < 0" is met. It's not subtract by 5 per second or even subtract by 5 per frame. It's subtract by 5 per loop. Btw, that would be another infinite loop.
Image
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: while loop trouble ?

Post by Cobalt »

I messed a long time with sprinting for my mod using the stuffcommands for the speed like that, but since darkplaces has a new physics QC file you can optionally activate, you can manage this alot easier in some ways.....so thats what I am doing now, but I was ' moderately' successful trying it with the stuff commands llike that. There is a tut here for footsteps sounds that I used as the main foundation, after all, it all ought to synchronize with the sounds in the end.

So in the playerpostthink() I had:

stuffspeed ();
playerfootstep ();

Code: Select all

void () stuffspeed =
{
	if (((self.watertype == CONTENT_WATER) || (self.watertype == CONTENT_SLIME)))
	{
		if ((self.velocity != puff_org))
		{
			if (((self.waterlevel > FIND_NEAREST) && !(self.items & IT_SUIT)))
			{
				stuffcmd (self, "-speed\n");
			}
			else
			{
				if (((self.waterlevel == FIND_NEAREST) && !(self.items & IT_SUIT)))
				{
					stuffcmd (self, "cl_forwardspeed 175\n");
					stuffcmd (self, "cl_backspeed 175\n");
					stuffcmd (self, "cl_sidespeed 150\n");
					self.walkvalue = CONTENT_EMPTY;
				}
				else
				{
					if ((self.items & IT_SUIT))
					{
						stuffcmd (self, "cl_forwardspeed 295\n");
						stuffcmd (self, "cl_backspeed 295\n");
						stuffcmd (self, "cl_sidespeed 270\n");
						self.runvalue = CONTENT_EMPTY;
					}
				}
			}
		}
	}
	if (((self.runvalue == CONTENT_EMPTY) || (self.walkvalue == CONTENT_EMPTY)))
	{
		if (((!self.waterlevel && checkbottom (self)) && (self.velocity != puff_org)))
		{
			stuffcmd (self, "cl_forwardspeed 200\n");
			stuffcmd (self, "cl_backspeed 200\n");
			stuffcmd (self, "cl_sidespeed 175\n");
		}
	}
};





void () playerfootstep =
{
	local float amp;
	local float s;

	if ((self.deadflag || (self.classname != "player")))
	{
		return;
	}
	if (!(self.flags & FL_ONGROUND))
	{
		return;
	}
	if (((time < self.nextfootstep) || (time < self.attack_finished)))
	{
		return;
	}
	if (((!self.waterlevel && checkbottom (self)) && (self.velocity != puff_org)))
	{
		if ((vlen (self.velocity) < 300))
		{
			amp = CAM_IDLE;
			self.nextfootstep = (time + 0.3);
			if (((self.runtime > self.sprint_finished) && (self.walktime == CONTENT_EMPTY)))
			{
				self.sprint_finished = ((time + (self.runtime - self.sprint_finished)) - FIND_NEAREST);
				if (((self.runtime - self.sprint_finished) >= fAutoBotNextThink))
				{
					self.sprint_finished = fAutoBotNextThink;
					stuffcmd (self, "bind shift \"+speed\"\n");
				}
			}
			self.walkvalue = vlen (self.velocity);
			if (((vlen (self.velocity) < MSG_UPDATENAME) && (self.velocity != puff_org)))
			{
				if ((vlen (self.velocity) < CAM_FOLLOW))
				{
					self.nextfootstep = (time + 0.6);
				}
				else
				{
					self.nextfootstep = (time + (vlen (self.velocity) / 9.5));
				}
				s = CONTENT_EMPTY;
			}
		}
		if ((vlen (self.velocity) > 300))
		{
			amp = DO_ADD;
			if (((self.runvalue == action) && (self.walktime != CONTENT_EMPTY)))
			{
				self.sprint_finished = (time + fAutoBotNextThink);
				self.runtime = (self.sprint_finished + fAutoBotNextThink);
			}
			self.nextfootstep = (time + 0.15);
			self.runvalue = vlen (self.velocity);
			updatebreath ();
		}
		if ((s != CONTENT_EMPTY))
		{
			s = (random () * DO_ADD);
			if ((s < FIND_NEAREST))
			{
				sound (self, CHAN_BODY, "boot1.wav", LMQUOTA_ARMOR, amp);
			}
			else
			{
				if ((s < FIND_FURTHEST))
				{
					sound (self, CHAN_DEV, "boot2.wav", LMQUOTA_ARMOR, amp);
				}
				else
				{
					if ((s < CAM_IDLE))
					{
						sound (self, CHAN_DEV, "boot3.wav", LMQUOTA_ARMOR, amp);
					}
					else
					{
						sound (self, CHAN_DEV, "boot4.wav", LMQUOTA_ARMOR, amp);
					}
				}
			}
		}
		else
		{
			sound (self, CHAN_AUTO, "slip.wav", LMQUOTA_ARMOR, amp);
		}
	}
	else
	{
		if (((!self.waterlevel && checkbottom (self)) && (self.velocity == puff_org)))
		{
			if ((self.runvalue || self.walkvalue))
			{
				sound (self, CHAN_AUTO, "breath2f.wav", FIND_NEAREST, ATTN_IDLE);
			}
			self.walkvalue = action;
			self.runvalue = action;
		}
	}
};


Things like making sure the player is on ground, in or out of water and I decided to give him some extra speed if he has the biosuit and in water, but that got trickier. There was other code that defined the .sprint_time but that was where the problem lied, as I was going to make that change depending on the type of character shosen and if he or she had a rune for example. vlen (self.velocity) is your most key float here
in that its a direct measurement you can look at and see those cl_speed values in realtime.
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: while loop trouble ?

Post by Cobalt »

Also of note, I happen to be experimenting with my bots angles, setting their v_angle ....and I happen to notice if you change it incrementally slowly as they move, but not exceeding 45 degrees up or down, it adds a more real looking effect to the model, as if its really taking steps walking and running. I bet if you set it to lean forward a little while running / sprinting it would be a sweet tweak....I'll have to try it someday. But heres the code I messed with:

Code: Select all

if ((self.goalentity != self && self.goalentity != world))
{
if (!EntityInFieldOfView (self.goalentity) && self.bot_action != BOT_FIGHTING)
{
if (self.goalentity.origin_z + self.view_ofs_z  > self.origin_z + self.view_ofs_z )
self.v_angle_x = (self.v_angle_x + (random () * 0.07));
if (self.goalentity.origin_z + self.view_ofs_z < self.origin_z + self.view_ofs_z )
self.v_angle_x = (self.v_angle_x - (random () * 0.07));

if (self.v_angle_x > 45 )
self.v_angle_x = 45;

if (self.v_angle_x < -45 )
self.v_angle_x = -45;
This is for when its moving to a goal, I was trying to have it keep looking in the direction of the goal as much as possible, but on one of the larger maps that are pretty much flat, and all the goal entities are on the same Z, it did a nice job of making the player look like its running.
Post Reply