先上图,方便查看。

以下文字代码,方便复制
============================分隔符==============================
// 角色视觉
function check_sight(_x, _y, _r, _dir, _range, _sight_h = 0) {
// 半径R内的对象列表
var _res_list = ds_list_create();
// 视野范围内的对象列表
var _sight_list = ds_list_create();
// 视野范围内的对象遮挡范围列表
var _blind_list = ds_list_create();
// 视野范围,逆时针第一条边为_sight_a1
var _sight_a1 = angle_dif(_dir, _range / 2);
var _sight_a2 = (_dir + _range / 2) % 360;
collision_ellipse_list(_x - _r, _y - _r, _x + _r, _y + _r, o_collision, false, true, _res_list, true);
for(var _i = 0; _i < ds_list_size(_res_list); _i++;) {
var _res = _res_list[| _i];
//draw_rectangle(_res.bbox_left, _res.bbox_top, _res.bbox_right, _res.bbox_bottom, 1)
// 计算物品四角与对象的角度
var _lt = point_direction(_x, _y, _res.bbox_left, _res.bbox_top);
var _lb = point_direction(_x, _y, _res.bbox_left, _res.bbox_bottom);
var _rt = point_direction(_x, _y, _res.bbox_right, _res.bbox_top);
var _rb = point_direction(_x, _y, _res.bbox_right, _res.bbox_bottom);
// 计算物品遮挡角度范围
var _dot_list = [[_lt, _res.bbox_left, _res.bbox_top]
, [_lb, _res.bbox_left, _res.bbox_bottom]
, [_rt, _res.bbox_right, _res.bbox_top]
, [_rb, _res.bbox_right, _res.bbox_bottom]]
// 升序排序 (引擎自带的这个排序函数有bug,排序不准)
//array_sort(_dot_list, function(_var1, _var2){ return _var1[0] - _var2[0];});
// 升序排序
for (var _k = 0; _k < array_length(_dot_list); _k++) {
for (var _j = _k + 1; _j < array_length(_dot_list); _j++) {
if _dot_list[_k][0] <= _dot_list[_j][0] continue;
var _tmp = _dot_list[_k][0];
_dot_list[_k][0] = _dot_list[_j][0];
_dot_list[_j][0] = _tmp;
}
}
var _angle1 = 0;
var _angle2 = 0;
// 如果物体跨越了第四第一象限,特殊处理
var _is_special = _dot_list[0][0] < 90 && _dot_list[3][0] > 270;
if _is_special {
_angle1 = _dot_list[2];
_angle2 = _dot_list[1];
} else {
_angle1 = _dot_list[0];
_angle2 = _dot_list[3];
}
// 能否看见物体
var _is_sight = false;
var _dif_angle1_sight1 = angle_dif(_angle1[0], _sight_a1);
var _dif_angle2_sight1 = angle_dif(_angle2[0], _sight_a1);
var _dif_angle2_sight2 = angle_dif(_angle2[0], _sight_a2);
// 如果物体超过视野横截宽度
if ((_dif_angle2_sight2 < 90 - _range / 2 && (_dif_angle1_sight1 > _dif_angle2_sight2 + 180 + _range / 2))
|| (_dif_angle1_sight1 > 270 + _range / 2 && _dif_angle2_sight2 < _dif_angle1_sight1 - 180 && _dif_angle2_sight1 > _range))
&& _dif_angle2_sight2 > 0 {
_angle1[0] = _sight_a1;
_angle2[0] = _sight_a2;
_is_sight = true;
}
// 如果_angle1在视野内, 且该点距离小于半径
else if (_dif_angle1_sight1 < _range && point_distance(_x, _y, _angle1[1], _angle1[2]) < _r) {
// 如果_angle2超过视野边界
if _dif_angle2_sight1 > _range _angle2[0] = _sight_a2;
_is_sight = true;
}
// 如果_angle2在视野内, 且该点距离小于半径
else if (_dif_angle2_sight1 < _range && point_distance(_x, _y, _angle2[1], _angle2[2]) < _r) {
// 如果_angle1超过视野边界
if _dif_angle1_sight1 > (_dif_angle2_sight1 + 180) _angle1[0] = _sight_a1;
_is_sight = true;
}
// 如果_angle1、_angle2均在视野内
else if (_dif_angle2_sight1 < _range && _dif_angle1_sight1 < _range) {
_is_sight = true;
}
// 如果_angle1或_angle2在视野内, 且与视野边缘碰撞
else if (_dif_angle1_sight1 < _range) || (_dif_angle2_sight1 < _range) {
if collision_line(_x, _y, _x + lengthdir_x(_r, _sight_a1), _y + lengthdir_y(_r, _sight_a1), _res, false, true) {
_angle1[0] = _sight_a1;
_is_sight = true;
}
else if collision_line(_x, _y, _x + lengthdir_x(_r, _sight_a2), _y + lengthdir_y(_r, _sight_a2), _res, false, true) {
_angle2[0] = _sight_a2;
_is_sight = true;
}
}
// 判断物品是否在视野内
if _is_sight {
// 是否被遮挡
var _is_blind = false;
// 计算物品高度
var _res_h = is_empty(_res[$ "obj_height"] != noone) ? _res[$ "obj_height"] : max(0, sprite_get_height(_res.sprite_index) - (_res.bbox_bottom - _res.bbox_top));
// 合并计算遮挡范围
var _blind_gth = blind_merge_gth(_x, _y, _sight_h, _res.x, _res.y, _res_h, _blind_list);
// 判断是否被遮挡
for(var _j = 0; _j < array_length(_blind_gth); _j++;) {
var _blind_a1 = _blind_gth[_j][0];
var _blind_range = _blind_gth[_j][1];
if angle_dif(_angle1[0], _blind_a1) <= _blind_range && angle_dif(_angle2[0], _blind_a1) <= _blind_range {
_is_blind = true;
break;
}
}
// 如果物品被阻挡,跳过
if _is_blind continue;
// 计算物品遮挡角度大小
var _a_range = angle_dif(_angle2[0], _angle1[0]);
// 保存物品遮挡角度及范围
ds_list_add(_blind_list, [_angle1[0], _angle1[1], _angle1[2], _a_range, _res_h, _res]);
// 保存物品
ds_list_add(_sight_list, _res);
}
}
ds_list_destroy(_res_list);
ds_list_destroy(_blind_list);
return _sight_list;
}
// 筛选出高度足够的遮挡物;合并有重叠的遮挡区域
function blind_merge_gth(_x, _y, _sight_h, _res_x, _res_y, _res_h, _blind_list) {
// 筛选出的遮挡物
var _blind_gth = [];
//draw_line(_x, _y, _res_x, _res_y)
for(var _i = 0; _i < ds_list_size(_blind_list); _i++;) {
var _i_a1 = _blind_list[| _i][0];
var _i_x = _blind_list[| _i][1];
var _i_y = _blind_list[| _i][2];
var _i_range = _blind_list[| _i][3];
var _i_h = _blind_list[| _i][4];
var _i_res = _blind_list[| _i][5];
var _dif_angle = angle_difference(point_direction(_x, _y, _i_res.x, _i_res.y), point_direction(_x, _y, _res_x, _res_y))
// 阻挡物的距离 在 目标物方向上的分量
//var _x_map = abs(point_distance(_x, _y, _i_res.x, _i_res.y) / cos(degtorad(_dif_angle)))
// 对象距离障碍物碰撞框的最近距离
var _i_d = point_to_rect_distance(_x, _y, _i_res)
// 目标物体被遮挡的高度
var _target_h = ((_i_h - _sight_h) / _i_d) * point_distance(_x, _y, _res_x, _res_y) + _sight_h
// 如果高度足够阻挡_res
if _target_h >= _res_h {
var if_merge = false;
for(var _j = 0; _j < array_length(_blind_gth); _j++;) {
var _j_a1 = _blind_gth[_j][0];
var _j_range = _blind_gth[_j][1];
// 如果遮挡区域有重叠,则将区域相加
var _angle_dif_a1 = angle_dif(_i_a1, _j_a1);
var _angle_dif_a2 = angle_dif((_i_a1 + _i_range) % 360, _j_a1);
if _angle_dif_a1 <= _j_range {
if _j_range < _angle_dif_a1 + _i_range {
_blind_gth[_j][1] = _angle_dif_a1 + _i_range;
if_merge = true;
break;
}
}
else if _angle_dif_a2 <= _j_range {
_blind_gth[_j][0] = _i_a1;
_blind_gth[_j][1] = angle_dif((_j_a1 + _j_range) % 360, _i_a1);
if_merge = true;
break;
}
}
// 如果遮挡区域无重叠,则添加该区域至列表
if !if_merge {
_blind_gth[array_length(_blind_gth)] = [_i_a1, _i_range];
}
}
}
return _blind_gth;
}
// 计算点到框的最短距离
function point_to_rect_distance(_x, _y, _rect) {
var _dx = max(_rect.bbox_left - _x, 0, _x - _rect.bbox_right);
var _dy = max(_rect.bbox_top - _y, 0, _y - _rect.bbox_bottom);
return sqrt(_dx * _dx + _dy * _dy);
}
// 计算两个角度的差值(不可用系统函数angle_difference()替代!)
function angle_dif(_angle1, _angle2) {
return (_angle1 - _angle2 + 360) % 360;
}
=============================分隔符============================