Tôi vừa mới tìm thấy bản thân mình bằng cách sử dụng traceline rất nhiều trong các plugin của tôi. Tôi nhận ra rằng đã có không bất kỳ hướng dẫn vì vậy tôi quyết định viết một.
Theory - Lý Thuyết
Traceline là gì, thực sự? Traceline là một hàm trong Half-Life Engine được sử dụng để vẽ các đường từ điểm này đến điểm khác trong một khung cảnh 3D. Nó có thể trả về thông tin, như người (hoặc những gì) bị trúng, và khác nhau bit hữu ích khác của thông tin.
Traceline được sử dụng trong tất cả các mod để xác định nơi một cầu thủ được tìm kiếm và bắn súng. Do đó, nó khá hữu ích để tìm hiểu làm thế nào để thao tác traceline ý thích của bạn.
Mod mà bạn đang kịch bản cho (trong trường hợp của tôi, CS) là tách biệt với Engine HL. Metamod (và nói rộng ra, AMX Mod X) nằm giữa DLL mod và engine HL. Điều này cho phép chúng ta khả năng để ngăn chặn bất cứ điều gì các DLL mod sẽ gửi đến engine, và ngược lại. Vì vậy, khi CS hỏi engine HL để tính toán một traceline, chúng ta có thể thay đổi hoàn toàn kết quả.
The Code
Chúng tôi sẽ sử dụng forwards trong Fakemeta trong nắm bắt thông tin liên lạc giữa CS và engine HL. Điều này có nghĩa chúng ta sẽ thấy các dữ liệu CS đã đi qua engine để tính toán một traceline.
PHP Code:
#include <amxmodx>
#include <fakemeta>public plugin_init()
{
register_plugin("Traceline Tutorial", "1.0", "Nomexous")
register_forward(FM_TraceLine, "traceline_forward")
}
public traceline_forward(Float:start[3], Float:end[3], conditions, id, trace)
{
// Our traceline forward.}
Float:start[3] Gốc mà từ đó bắt đầu traceline.
Float:end[3] Gốc các traceline được vẽ đến.
conditions Xác định có hay không để bỏ qua các thực thể nhất định khi vẽ traceline.
Values can be DONT_IGNORE_MONSTERS, IGNORE_GLASS,IGNORE_MISSLE, and IGNORE_MONSTERS.
id Đây là thực thể bỏ qua khi vẽ traceline. Có lẽ, bạn đang vẽ từ nguồn gốc của một thực thể (đó là bên trong nó) đến thời điểm khác. Với tracelines chơi, id là chỉ số người chơi của bất cứ ai đang bắn những traceline.
trace Kết quả theo dõi của chúng tôi. Đây là phần quan trọng nhất. Nó chứa các thông tin về những gì đã đạt, trong số những thứ khác. Sử dụng get_tr2 và set_tr2 với nó.
The Trace Result
Đây là phần thú vị nhất. Theo dõi biến chứa thông tin chi tiết, có thể được truy xuất như đã nêu:
PHP Code:
public traceline_forward(Float:start[3], Float:end[3], conditions, id, trace)
{
// Có nhiều TR_ * hằng số hơn được liệt kê ở đây; đây là những // Cái tôi sử dụng nhiều nhất.
new hit = get_tr2(trace, TR_pHit)
// Điều gì đã ảnh hưởng bởi traceline. Nó sẽ hoặc là một chỉ số người chơi, // Chỉ số thực thể, 0 (một phần của bản đồ), hoặc -1 (không đánh bất cứ điều gì;
// Không xảy ra với người chơi tracelines).
new hitgroup = get_tr2(trace, TR_iHitgroup)
// Nếu traceline đánh người chơi khác, lợi nhuận sẽ được HIT_HEAD, // HIT_CHEST, HIT_LEFTLEG ... vv Nếu traceline nhấn một phần của
// Bản đồ, điều này trả về HIT_GENERIC.
new Float:fraction
get_tr2(trace, TR_flFraction, fraction)
// Trả về một số giữa 0.0 và 1.0, chỉ ra cách xa // Traceline đi đầu đến cuối trước khi nó chạm một cái gì đó. tùy thuộc
// Trên những điều kiện đã được thông qua để traceline hàm chuyển tiếp này,
// Nó, hoặc có thể là một bức tường hoặc một tổ chức khác.
new Float:end_origin[3]
get_tr2(trace, TR_vecEndPos, end_origin)
// Kết thúc chính thức của traceline. Không nhất thiết phải giống như // Số thứ hai thông qua traceline hàm chuyển tiếp này.
new Float:normal[3]
get_tr2(trace, TR_vecPlaneNormal, normal)
// Trả về 1 đơn vị vector dài bình thường đến chỗ nó đánh. //Lưu ý rằng "bình thường" có một ý nghĩa đặc biệt ở đây. Nó không có nghĩa là "thường xuyên".}
Now, changing these value is as easy as using the set_tr2 function.
A Potentially Evil Plugin
I'm sure you've all played on a server which allowed headshots only. Good practice; body shots do no damage, headshots kill instantly, yadda yadda. But what if we could redirect a shot on any part of the body to the head? Foot shot turns into a headshot? Amazing!
PHP Code:
public traceline_forward(Float:start[3], Float:end[3], conditions, id, trace)
{
set_tr2(trace, TR_iHitgroup, HIT_HEAD)
return FMRES_IGNORED}
But it gets kinda hard trying to hide the fact that the blood from a headshot came out of the foot, or stomach, or whatever part of the body you happened to hit. What you want is for blood to also be redirected to the head. Because this relies on traceline, we are still fully in control:
PHP Code:
public traceline_forward(Float:start[3], Float:end[3], conditions, id, trace)
{
set_tr2(trace, TR_iHitgroup, HIT_HEAD) // Redirect shot to head
// Variable angles doesn't really have a use here.
static hit, Float:head_origin[3], Float:angles[3]
hit = get_tr2(trace, TR_pHit) // Whomever was shot
engfunc(EngFunc_GetBonePosition, hit, 8, head_origin, angles) // Find origin of head bone (8)
set_tr2(trace, TR_vecEndPos, head_origin) // Blood now comes out of the head!
return FMRES_IGNORED}
You can of course change whom you are shooting. Consider this anti-team attack plugin for cs:
PHP Code:
#include <amxmodx>
#include <fakemeta>
#include <cstrike>public plugin_init()
{
register_plugin("Traceline Tutorial - No TA", "1.0", "Nomexous")
register_forward(FM_TraceLine, "traceline_forward")
}
public traceline_forward(Float:start[3], Float:end[3], conditions, id, trace)
{
static hit
hit = get_tr2(trace, TR_pHit)
// Variable id is shooter's index.
if (cs_get_user_team(id) == cs_get_user_team(hit))
{
// Redirect onto himself!
set_tr2(trace, TR_pHit, id)
}
return FMRES_IGNORED}
I've submitted a plugin (Shot Administration) that demonstrates the evil capabilities of manipulating traceline. Take a look; tracehull is also hooked (for knife damage).
Less Evil Uses of Traceline
We will now use tracelines to do our bidding outside the context of player aiming. Using engfunc(), we can call draw our own tracelines to see what we hit. Of course, we're not actually shooting and dealing damage, but with the information that the trace result gives us, it can be just as useful.
Lets find out if two origins are in line of sight:
PHP Code:
stock bool:is_in_line_of_sight(Float:origin1[3], Float:origin[2], bool:ignore_players = true)
{
new trace = 0
engfunc(EngFunc_TraceLine, origin1, origin2, (ignore_players ? IGNORE_MONSTERS : DONT_IGNORE_MONSTERS), 0, trace)
new Float:fraction
get_tr2(trace, TR_flFraction, fraction)
return (fraction == 1.0) ? true : false}
Now, let's make use of the TR_vecPlaneNormal part of our trace result. There are multiple things this is useful for. Here, I'll outline how to draw a laser normal to a surface.
When a trace hits something, TR_vecPlaneNormal will have a unit vector (1 unit in length) stored to it, pointing perpendicularly away from surface at the spot it hit. To get the endpoint of the laser, we merely need to extend the length of the normal vector and add it to the origin of where we want the laser to start from. Here is a sample:
PHP Code:
#include <amxmodx>
#include <fakemeta>
#define PLUGIN "Draw Normal Laser Example"
#define VERSION "1.0"
#define AUTHOR "Nomexous"new beampointpublic plugin_precache()
{
// Needed to show the laser.
beampoint = precache_model("sprites/laserbeam.spr")
}
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
// I included the entire plugin because in order to draw the laser, you need to precache a sprite. Incorporate
// these elements into your own plugin.
// The shoot_laser() will (if the entity is on the floor) fire a laser from the entity, normal to the surface it's resting on.}
public shoot_laser(ent)
{
// We get the origin of the entity.
new Float:origin[3]
pev(ent, pev_origin, origin)
// We want to trace down to the floor, if it's there.
new Float:traceto[3]
traceto[0] = origin[0]
traceto[1] = origin[1]
traceto[2] = origin[2] - 10.0
new trace = 0
// Draw the traceline. We're assuming the object is resting on the floor.
engfunc(EngFunc_TraceLine, origin, traceto, IGNORE_MONSTERS, ent, trace)
new Float:fraction
get_tr2(trace, TR_flFraction, fraction)
// If we didn't hit anything, then we won't get a valid TR_vecPlaneNormal.
if (fraction == 1.0) return
new Float:normal[3]
get_tr2(trace, TR_vecPlaneNormal, normal)
// We'll multiply the the normal vector by a scalar to make it longer.
normal[0] *= 400.0 // Mathematically, we multiplied the length of the vector by 400*(3)^(1/2),
normal[1] *= 400.0 // or, in words, four hundred times root three.
normal[2] *= 400.0
// To get the endpoint, we add the normal vector and the origin.
new Float:endpoint[3]
endpoint[0] = origin[0] + normal[0]
endpoint[1] = origin[1] + normal[1]
endpoint[2] = origin[2] + normal[2]
// Finally, we draw from the laser!
draw_laser(origin, endpoint, 100) // Make it stay for 10 seconds. Not a typo; staytime is in 10ths of a second.}
public draw_laser(Float:start[3], Float:end[3], staytime)
{
message_begin(MSG_ALL, SVC_TEMPENTITY)
write_byte(TE_BEAMPOINTS)
engfunc(EngFunc_WriteCoord, start[0])
engfunc(EngFunc_WriteCoord, start[1])
engfunc(EngFunc_WriteCoord, start[2])
engfunc(EngFunc_WriteCoord, end[0])
engfunc(EngFunc_WriteCoord, end[1])
engfunc(EngFunc_WriteCoord, end[2])
write_short(beampoint)
write_byte(0)
write_byte(0)
write_byte(staytime) // In tenths of a second.
write_byte(10)
write_byte(1)
write_byte(255) // Red
write_byte(0) // Green
write_byte(0) // Blue
write_byte(127)
write_byte(1)
message_end()
}
Well, that's all I have for now. Hopefully, you've learned more about traceline and can take advantage of its features!
0 nhận xét:
Post a Comment