Help with hand to hand combat...
by David Dougher · in General Discussion · 10/09/2002 (12:44 pm) · 10 replies
It seemed like such a simple idea at the time... I wanted to create a basic hand-to-hand combat system while not duplicating the work that had already been done to make the projectile system. After playing with the Armor::damage function and the projectile system calls I was able to have it give me the location of where the player was hit when you fired a bullet. So it seemed a simple leap to get it to work for a hand-to-hand combat system. I would animate the sword and when its bounding box contacted the bounding box of the player I would fire off an "invisible projectile" down the sword's length. It would have a slow rate of travel and a very short lifespan so it would not reach past the end of the weapon. The projectile would contact the character's bounding box and cause the damage while giving me the location of the damage as well.
It would be wickedly fast, and it would not require creating an additional layer of collision boxes and a testing mechanism in code. By moving the muzzlepoint and using a pattern vector of fire I could also achieve hand-to-hand damage with axes, hammers or any other hand held object.
I initially tried it out by firing off a "pattern" of projectiles that I could see that matched a simple animated sword swipe. It worked fine, cutting down my ai opponent. But for complicated sword moves trying to exactly match a pattern would use a huge number of shells and bog down the server in heavy combat. The basic idea worked fine and so I tried to move on to the next part which was to get the bounding box of the sword to fire a projectile when it encountered the bounding box of another player or aiBot.
I started by placing a muzzle point for the sword at the top of the handle so I could fire it down the blade when I collided with the opposing player...
At this point my tests ground to a screeching halt. For three days I have tried to find a way to capture the collision data in script. The sword passes thru the bot I created and does not seem to send off any indication that the object has collided. I can bump into the bot and I get messages forever... So, I am looking for two things...
1. I need a way to capture the initial collision between my sword's bounding box and the opponents bounding box so I can trigger my projectile. I know it must be there I just can't find the right function.
2. I need to make sure that the vector my projectile travels is always from the "muzzlepoint" at the top of the handle to the tip of the sword point.
Some of you math whizzes out there who know the vector and matrix calculations and are familiar with the Armor::damage function may be able to help...
Thanks in advance.
It would be wickedly fast, and it would not require creating an additional layer of collision boxes and a testing mechanism in code. By moving the muzzlepoint and using a pattern vector of fire I could also achieve hand-to-hand damage with axes, hammers or any other hand held object.
I initially tried it out by firing off a "pattern" of projectiles that I could see that matched a simple animated sword swipe. It worked fine, cutting down my ai opponent. But for complicated sword moves trying to exactly match a pattern would use a huge number of shells and bog down the server in heavy combat. The basic idea worked fine and so I tried to move on to the next part which was to get the bounding box of the sword to fire a projectile when it encountered the bounding box of another player or aiBot.
I started by placing a muzzle point for the sword at the top of the handle so I could fire it down the blade when I collided with the opposing player...
At this point my tests ground to a screeching halt. For three days I have tried to find a way to capture the collision data in script. The sword passes thru the bot I created and does not seem to send off any indication that the object has collided. I can bump into the bot and I get messages forever... So, I am looking for two things...
1. I need a way to capture the initial collision between my sword's bounding box and the opponents bounding box so I can trigger my projectile. I know it must be there I just can't find the right function.
2. I need to make sure that the vector my projectile travels is always from the "muzzlepoint" at the top of the handle to the tip of the sword point.
Some of you math whizzes out there who know the vector and matrix calculations and are familiar with the Armor::damage function may be able to help...
Thanks in advance.
About the author
Owner - Pariah Games, Adjunct Professor - Bristol Community College, Mentor - Game Design - Met School Newport, Mentor - Game Design - Met School Providence
#2
However, you must test the collisions on the server side in order to guarantee that the player doesn't cheat in multiplayer mode. So when you activate an animated move the animation is not run on the server side - only the client side. So no server side collision test will work unless the collision is reported by the object being hit.
As it stands now, if we tried to run the test you suggest or look for the collision I was originally aiming for we cannot test on the server from the player side. If we test on the client side we invite false hits and cheats.
The solution would appear to be that we must activate a class of animations that do run server-side and test for collisions there, and we must get the recipient of the attack to report the collision.
10/10/2002 (3:41 pm)
Actually, thinking about this whole process and your solution, I believe I understand that there is an underlying problem I had not considered. This problem is that animations are not played out on the server side for performance reasons. However, you must test the collisions on the server side in order to guarantee that the player doesn't cheat in multiplayer mode. So when you activate an animated move the animation is not run on the server side - only the client side. So no server side collision test will work unless the collision is reported by the object being hit.
As it stands now, if we tried to run the test you suggest or look for the collision I was originally aiming for we cannot test on the server from the player side. If we test on the client side we invite false hits and cheats.
The solution would appear to be that we must activate a class of animations that do run server-side and test for collisions there, and we must get the recipient of the attack to report the collision.
#3
The advantage of combining the two is that you not only get the damage applied through an already tested method, but you can also add any additional features that are currently available for projectiles and they will work as well - I am specifically thinking of the generation of a different animation when you hit a character rather than a regular object that is in a recent code snippet.
10/10/2002 (4:03 pm)
Check that. It is not necessary to animate server-side if the hit is properly reported through the client being struck server-side. Trying to animate even a subclass of animations would bring the server to a crawl in a big battle. So the raycast idea you have from base to tip would work, expecially if we combined it with my projectile idea. Cast a ray once every frame or two of of animation. If there is a collision, then fire an invisible projectile from the muzzle point of the sword base along the same vector as the raycast. This is easy since you have both points. Now, the projectile hits the object and the object reports collision, damage and location.The advantage of combining the two is that you not only get the damage applied through an already tested method, but you can also add any additional features that are currently available for projectiles and they will work as well - I am specifically thinking of the generation of a different animation when you hit a character rather than a regular object that is in a recent code snippet.
#4
------------------------
Wait a second: In Tribes 2 if you were in third person, doing an animation, and you fired a gun, it would come out of the gun in the right direction, so even if the animation isnt doen server side, the finding of muzzle points and directions is!
10/10/2002 (4:12 pm)
Hmm so you are saying do server side raycasting constantly is slow? Well perhaps you could do client side until a collision is decided, then a server side to verify, basically what you are doing with the projectile. This seems faster to me?------------------------
Wait a second: In Tribes 2 if you were in third person, doing an animation, and you fired a gun, it would come out of the gun in the right direction, so even if the animation isnt doen server side, the finding of muzzle points and directions is!
#5
The hit damage and location is also reported server side thru an already secured, tested method.
Think I'll go code browsing...
10/10/2002 (4:19 pm)
I should add that this has a second advantage of being relatively secure. The raycast is being generated client-side by the attacking player which means it could be corrupted, however, there is no advantage to reporting false hits because the projectile is being launched server-side and is tested server-side. Trying to report false collisions as an attacker would not do anything but bog down your own system.The hit damage and location is also reported server side thru an already secured, tested method.
Think I'll go code browsing...
#6
Simply do the raycast, calculate the hit, if hit, spawn whatever type of object you want at the explosion point. Call the objects TakeDamage method to cause it harm directly etc.
Projectiles in this case have no value.
Phil.
10/10/2002 (4:20 pm)
David, you gain nothing by doing the raycast AND projectile. The raycast is exactly what the projectile does anyway.Simply do the raycast, calculate the hit, if hit, spawn whatever type of object you want at the explosion point. Call the objects TakeDamage method to cause it harm directly etc.
Projectiles in this case have no value.
Phil.
#7
This is what I thought was being done.
A raycast is being done on the client side as part of the animation looking for a hit. We are doing the raycast client side becuase the on the server side no animation is being done and therefore there is no way to test for a collision between the weapon and the opposing player.
That raycast, because it is being created on the client side is not safe, (A hacker could simply report misses that are hits by extending the length of the raycast further than the length of the weapon.) So, we need to create a server side situation where we can test the reported raycast collision and verify that it really is a legitimate hit.
If the raycast causes the server to fire a projectile along the same path, it removes the ability to cheat since the server now controls the projectile and the length it can travel. When it hits the opposing player it will register in the armor damage() function (again server side). In that function the addition of the following small piece of code will give you the location where the player was hit.
function Armor::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
//As a test first say where they got hit
%result = %obj.getDamageLocation(%position);
echo("Impact Damage reported at:" SPC %result);
The string contains information like "torso back left side". Parsing this string will allow you to say that you hit a character, where you hit the character, modify the damage done by looking to see if the character was shielded on that side (or increasing the damage if you hit the character from behind).
I can see that I could call the damage() function directly from the raycast, but doesn't that put the hit in the hands of the player and not the server? If the hacker modifies the raycast what could possibly be done on the server-side to catch the hack?
I'll admit I have been looking at this so long that I'm getting punchy. The solution you propose is undoubtedly correct. I just want to make sure that it not only works but that it can't be easily compromised and I understand why it works...
10/10/2002 (5:23 pm)
I guess I'm still missing something here. This is what I thought was being done.
A raycast is being done on the client side as part of the animation looking for a hit. We are doing the raycast client side becuase the on the server side no animation is being done and therefore there is no way to test for a collision between the weapon and the opposing player.
That raycast, because it is being created on the client side is not safe, (A hacker could simply report misses that are hits by extending the length of the raycast further than the length of the weapon.) So, we need to create a server side situation where we can test the reported raycast collision and verify that it really is a legitimate hit.
If the raycast causes the server to fire a projectile along the same path, it removes the ability to cheat since the server now controls the projectile and the length it can travel. When it hits the opposing player it will register in the armor damage() function (again server side). In that function the addition of the following small piece of code will give you the location where the player was hit.
function Armor::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
//As a test first say where they got hit
%result = %obj.getDamageLocation(%position);
echo("Impact Damage reported at:" SPC %result);
The string contains information like "torso back left side". Parsing this string will allow you to say that you hit a character, where you hit the character, modify the damage done by looking to see if the character was shielded on that side (or increasing the damage if you hit the character from behind).
I can see that I could call the damage() function directly from the raycast, but doesn't that put the hit in the hands of the player and not the server? If the hacker modifies the raycast what could possibly be done on the server-side to catch the hack?
I'll admit I have been looking at this so long that I'm getting punchy. The solution you propose is undoubtedly correct. I just want to make sure that it not only works but that it can't be easily compromised and I understand why it works...
#8
You don't get the damage location but it would be a simple change for me to take the info received and feed it to the victim's armor::damage() function which is also server-side. That way the hit location can be determined and actual damage can be adjusted by things like shield effects and backstab.
Thanks!
10/10/2002 (6:31 pm)
Ok, I think I get how you did it. You are using a scripted callback to have the hit returned to the weapon doing the damage - which is on the server side. Then you can apply the damage directly to the character hit.You don't get the damage location but it would be a simple change for me to take the info received and feed it to the victim's armor::damage() function which is also server-side. That way the hit location can be determined and actual damage can be adjusted by things like shield effects and backstab.
Thanks!
#9
shapebaseimage::onImageIntersect(%this,%player,%slot,%startvec,%endvec)
One thing I had missed was that I was passing enough parameters but handnt read enough parameters for the function to work.
What the callback function does is do the raycast between startvec and endvec, ignoring %player and called Armor::onDamage when it gets a player hit.
Only, it still doesnt quite work :)) I think its the client/server id'ing thats the issue.
Phil.
10/13/2002 (8:01 am)
Thats it. I wrote a function in shapebase which finds the damage nodes, it calculates thier position in world space (so the raycast works) then passes those into a script function: shapebaseimage::onImageIntersect(%this,%player,%slot,%startvec,%endvec)
One thing I had missed was that I was passing enough parameters but handnt read enough parameters for the function to work.
What the callback function does is do the raycast between startvec and endvec, ignoring %player and called Armor::onDamage when it gets a player hit.
Only, it still doesnt quite work :)) I think its the client/server id'ing thats the issue.
Phil.
#10
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3374
It is basically a complete implementation of hand to hand combat and locational damage for torque. It's kind of long (60 pages... :) ) But it works, so you might want to check it out. Hope it helps!
10/13/2002 (3:54 pm)
David, you may want to take a look at my recently submitted resource (I hope this link works)http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3374
It is basically a complete implementation of hand to hand combat and locational damage for torque. It's kind of long (60 pages... :) ) But it works, so you might want to check it out. Hope it helps!
Torque Owner Max Robinson
This one would require a little bit of engine coding...
Since usually a weapon will only have 1 or 2 cutting edges, you could implement a system in which you place pairs of nodes on the model to indicate the edges. For instance, on a sword, a single point at the base of the blade and the tip, or on a 2 headed axe, one at the top and bottom of each eadge. Then, while swinging, you could do a raycast from point to point.
If you dont have access to engine code, then this idea modifies too much, but you can still do raycasting.
Just in case you don't know, a raycast (esp script) is done by calculating a line from one point to another and when the line collides with an object that is of the type of mask(s) you set to be valid, the point, normal, and object are returned.
The order they are returned is:
(1 word) (3 words) (3 words)
< object > < position > < normal >
I'm pointing this about because if you want to use these to get information you need to use getWord(
So, for example:
containerRayCast(%pos1, %pos2, $TypeMasks::PlayerObjectType, %player);
Will tell you the information about any players inbetween %pos1 and %pos2, excluding %player.
How can you use this?
Use a fixed number for the length of the sword, say 3. Now use getMuzzleVector to get the vector of the muzzlepoint, and add vector * length to the muzzle position. Use this as the endpoint, and muzzle position as start point. Just do the same mask/object settings as that example and you have a faster method of detecting sword collisions.
I hope this helps.