Author Topic: Looking At Player/Object  (Read 6867 times)

I want to make it so that whenever my crosshair is pointing at another player I can type something like
/setScale <scale> to reset their size, or something like that. I'm just very unfamiliar with things where
it detects what I'm pointing at or detects where I'm looking at. I think it has to do with vector or something?
I'm not sure... Can someone show me where to start to learn about this?

So, to shoot a raycast where you're looking, you have to do a couple of things.

1. Get the position that the eye is at, this is the start of the raycast.
2. Get the unit vector for where the person is looking. This is a normalized (exactly 1 long) vector that gives the point exactly 1 unit in front of the eye.
3. Stretch the unit vector to be longer than 1 unit. 1 unit is 2 brick studs, so I assume you want a longer range.
4. Add the stretched unit vector to the eye's position. This is the end of the raycast.
5. Cast the ray. The syntax for casting a ray is containerRaycast( start , end , typemask , exclude ).


1. Get the player's eye position
%startPoint = %player.getEyePoint();

2. Get the unit vector for where the person is looking.
%eyeVector = %player.getEyeVector();

3. Stretch the unit vector.
%stretchVector = vectorScale(%eyeVector, 50);

4. Add the stretched vector to the starting point
%endPoint = vectorAdd(%startPoint, %stretchVector);

5. Cast the ray.
%rayResult = containerRaycast(%startPoint, %endPoint, $TypeMasks::PlayerObjectType, %player);

So then just make a function for setting your look target's scale..

Code: [Select]
function serverCmdSetScale(%client, %size) {
    %player = %client.player;
    %startPoint = %player.getEyePoint();
    %eyeVector = %player.getEyeVector();
    %stretchVector = vectorScale(%eyeVector, 50);
    %endPoint = vectorAdd(%startPoint, %stretchVector);
    %rayResult = containerRaycast(%startPoint, %endPoint, $TypeMasks::PlayerObjectType, %player);
    %targetPlayer = getWord(%rayResult, 0);
    if(isObject(%targetPlayer))
        %targetPlayer.setScale(%size SPC %size SPC %size);
    else
        messageClient(%client, '', "Target not found.");
}

Also, you can compress all that code into pretty much one line..

Code: [Select]
function serverCmdSetScale(%client, %size) {
    return isObject(%targetPlayer = getWord(containerRayCast(%client.player.getEyePoint(), vectorAdd(%client.player.getEyePoint(), vectorScale(%client.player.getEyeVector(), 50)), $TypeMasks::PlayerObjectType, %client.player),0)) ? %targetPlayer.setScale(%size SPC %size SPC %size) : messageClient(%client, '', "Target not found.");
}

Very helpful, thank you trinick.

Also, if you don't want the raycast to go through bricks and stuff you can do %rayResult = containerRaycast(%startPoint, %endPoint, $TypeMasks::PlayerObjectType | $TypeMasks::FxBrickObjectType | $TypeMasks::VehicleObjectType, %player);

There's a list of typemasks here:
http://forum.blockland.us/index.php?topic=212880.0

Of course if you do this, you'll need to make sure that the raycast hit a player. After checking if it hit something, you can either do A:
if(%target.getClassName() $= "Player")
Or B:
if(%target.getType() & $TypeMasks::PlayerObjectType)
« Last Edit: September 24, 2014, 07:58:17 AM by jes00 »

For that matter, you can just use $TypeMasks::All. But yeah, good point.

For that matter, you can just use $TypeMasks::All. But yeah, good point.
But then the raycast wouldn't go through corpses or explosions or items or projectiles or water or a whole bunch of other stuff.

Exactly. Anything that would obstruct your view of the player.

Is there a way to do this in a conic, rather than linear fashion?  Like for instance, something becomes within 20° of my crosshair?

Mmmm sort of. The best way is to do a box search in front of your player, then take all the objects it picks up and calculate if they're within 20 degrees of your crosshair with math. Then shoot a raycast out to make sure you can actually see them, and remove the ones you can't see from the list.

To do a box search in front of the player..

Code: [Select]
function Player::isInView(%player) {
    %boxCenter = vectorAdd(%player.getEyePoint(), vectorScale(%player.getEyeVector(), 10));
    initContainerBoxSearch(%boxCenter, "20 20 20", $TypeMasks::PlayerObjectType);
    while(%obj = containerSearchNext()) {
        //check if they're within line of sight, continue if not. Check also to make sure it's not the same player.
        %list[(%listCount++) - 1] = %obj;
    }
    for(%i = 0; %i < %listCount; %i++) {
        if(isObject(containerRaycast(%player.getEyePoint(), %list[%i].getHackPosition(), $TypeMasks::All, %player)))
            continue;
        %finalList = %finalList SPC %list[%i];
    }
    %finalList = trim(%finalList);
    return finalList;
}

So, then, to check if they're within a 20 degree angle..

(Thanks to Port for the math code)
Code: [Select]
function Player::isInViewCone(%this, %target, %angle) {
    %direct = vectorNormalize(vectorSub(%target.getHackPosition(), %this.getEyePoint()));
    %product = vectorDot(%this.getEyeVector(), %direct);

    if (%product >= 1 - (%angle / 360) * 2)
      return true;
    return false;
}

So, together..

Code: [Select]
function Player::isInViewCone(%this, %target, %angle) {
    %direct = vectorNormalize(vectorSub(%target.getHackPosition(), %this.getEyePoint()));
    %product = vectorDot(%this.getEyeVector(), %direct);

    if (%product >= 1 - (%angle / 360) * 2)
      return true;
    return false;
}


function Player::isInView(%player) {
    %boxCenter = vectorAdd(%player.getEyePoint(), vectorScale(%player.getEyeVector(), 10));
    initContainerBoxSearch(%boxCenter, "20 20 20", $TypeMasks::PlayerObjectType);
    while(%obj = containerSearchNext()) {
        if(%player != %obj && %player.isInViewCone(%obj, 20))
            %list[(%listCount++) - 1] = %obj;
        }
    }
    for(%i = 0; %i < %listCount; %i++) {
        if(isObject(containerRaycast(%player.getEyePoint(), %list[%i].getHackPosition(), $TypeMasks::All, %player)))
            continue;
        %finalList = %finalList SPC %list[%i];
    }
    %finalList = trim(%finalList);
    return finalList;
}
« Last Edit: September 25, 2014, 06:41:46 PM by $trinick »

Exactly. Anything that would obstruct your view of the player.
Also, because of the $TypeMasks::FxBrickAlwaysObjectType typemask, wouldn't it also stop at bricks with raycasting off? Or does that typemask detect something else?

Aren't you missing some starting brackets $trinick?

Aren't you missing some starting brackets $trinick?

Nope, he just likes to put brackets on the same line (yuck).

Nope, he just likes to put brackets on the same line (yuck).
Code: [Select]
function Player::isInViewCone(%this, %target, %angle)
    %direct = vectorNormalize(vectorSub(%target.getHackPosition(), %this.getEyePoint()));
    %product = vectorDot(%this.getEyeVector(), %direct);

    if (%product >= 1 - (%angle / 360) * 2)
      return true;
    return false;
}
I agree to the yuck. However he did forget the one on this function.

Whoopsie. You're right, I don't know how I forgot that one.

I prefer brackets on the same line because it reduces pointless whitespace in the code. Same reason I do this:

Code: [Select]
if(%variable == 1) {
    // do true
} else {
    // do false
}

It looks much nicer than this bloated, verbose crap:

Code: [Select]
if(%variable == 1)
{
    // do true
}
else
{
    // do false
}

-snip-
This is fascinating.  I'm definitely saving this.

In this way, could I make text change on-screen by saying something like "The nearest bot to your view is (angles)"?