以下是翻译结果:
Feypath的光照引擎
这是一个短视频,展示了Feypath的光照引擎。这个引擎使用一个自定义的方法,已经在我的基于砖块的游戏中得到了很好的效果。如果你感兴趣,可以查看我的光照对象的代码(请自由问任何问题):
debug_m = true
tile_size = 16
light_radius = 6
level_width = 16
level_height = 14
tiles_processed = 0
rects_created = 0
verts_drawn = 0
shadow_surface = surface_create(256, 224)
function init_shadow_surface(){
if not surface_exists(shadow_surface) shadow_surface = surface_create(256, 224)
surface_set_target(shadow_surface)
draw_clear_alpha(c_black, 1)
}
global.map = layer_tilemap_get_id("Tiles")
//Declare level data array
tile_data = array_create(level_width)
for (var _column = 0; _column < level_width; _column++) {
tile_data[_column] = array_create(level_height)
}
//Populate level data array
for (var _column = 0 ; _column < level_width ; _column ++){
for (var _row = 0 ; _row < level_height ; _row ++){
tile_data[_column][_row] = tilemap_get(global.map, _column, _row) != 0
}
}
function get_tile_at_pixel(_pixel_x,_pixel_y){
return tile_data[floor(_pixel_x / tile_size)][floor(_pixel_y / tile_size)]
}
function generate_skip_tiles_array(){
var _skip_tiles = array_create(level_width)
for (var _column = 0; _column < level_width; _column++) {
_skip_tiles[_column] = array_create(level_height)
}
return _skip_tiles
}
//DRAWING STUFF
function draw_rectangles(){
verts_drawn = 0
tiles_processed = 0
rects_created = 0
var _start_column = max(0, floor(x / tile_size) - light_radius)
var _end_column = min(level_width, floor(x / tile_size) + light_radius)
var _start_row = max(0, floor(y / tile_size) - light_radius)
var _end_row = min(level_height, floor(y / tile_size) + light_radius)
var _skip_tiles = generate_skip_tiles_array()
init_shadow_surface()
draw_set_color(c_white)
draw_circle_colour(x, y , light_radius * tile_size, c_white, c_black, 0)
for (var _column = _start_column ; _column < _end_column; _column ++){
for (var _row = _start_row ; _row < _end_row; _row ++){
if tile_data[_column][_row] tiles_processed ++
//Check if we can start the rectangle, the rectangle can be started if the tile is solid and it does not exist in _skip_tiles
if tile_data[_column][_row] and not _skip_tiles[_column][_row]{
rects_created ++
var _rectangle_width = 1
var _rectangle_height = 1
//checking how wide our rectangle will be
var _right_border_reached = false
while not _right_border_reached{
var _next_column = _column + _rectangle_width
if _next_column >= _end_column _right_border_reached = true
else if (not tile_data[_next_column][_row]) or _skip_tiles[_next_column][_row] _right_border_reached = true
else {
_rectangle_width ++
_skip_tiles[_next_column][_row] = true
}
}
//using the info about rectangle width, we check how many rows we can add (if any)
var _failed_to_add_row = false
var _next_row = _row + 1
var _next_column = _column
while not _failed_to_add_row{
if _next_row >= _end_row _failed_to_add_row = true
else if (not tile_data[_next_column][_next_row]) or _skip_tiles[_next_column][_next_row]{
_failed_to_add_row = true
}
else{
_next_column ++
if _next_column == _column + _rectangle_width{
for (var _skip_col = _column; _skip_col < _column + _rectangle_width; _skip_col ++){
_skip_tiles[_skip_col][_next_row] = true
}
_rectangle_height ++
_next_row ++
_next_column = _column
}
}
}
//draw the rectangle DEBUG ONLY
if debug_m {
draw_set_color(c_white)
draw_rectangle(_column * tile_size, _row * tile_size, (_column + _rectangle_width) * tile_size,(_row + _rectangle_height) * tile_size, 1)
}
//Find the two corners
var _left_x = _column * tile_size
var _upper_y = _row * tile_size
var _right_x = (_column + _rectangle_width) * tile_size
var _bottom_y =(_row + _rectangle_height) * tile_size
var _corner_pairs = [
[_left_x, _upper_y, _right_x, _upper_y],
[_left_x, _upper_y, _right_x, _bottom_y],
[_left_x, _upper_y, _left_x, _bottom_y],
[_left_x, _bottom_y, _right_x, _bottom_y],
[_right_x, _upper_y, _left_x, _bottom_y],
[_right_x, _upper_y, _right_x, _bottom_y]
]
var _largest_angle = 0
var _largest_pair = 0
for (var _corner_pair = 0; _corner_pair < 6; _corner_pair ++){
var _x1 = _corner_pairs[_corner_pair][0]
var _y1 = _corner_pairs[_corner_pair][1]
var _x2 = _corner_pairs[_corner_pair][2]
var _y2 = _corner_pairs[_corner_pair][3]
var _ang1 = point_direction(x, y, _x1, _y1);
var _ang2 = point_direction(x, y, _x2, _y2);
var _current_angle = abs(angle_difference(_ang1,_ang2))
if _current_angle > _largest_angle{
_largest_angle = _current_angle
_largest_pair = _corner_pair
}
}
//The "opposing pair" are the corners currently not present in the largest pair - we need to use this in a bit if the largest pair form a diagonal in the rectangle
var _opposing_pair = (_largest_pair + 3) mod 6
// make the corner points more readable
var _point_1_x = _corner_pairs[_largest_pair][0]
var _point_1_y = _corner_pairs[_largest_pair][1]
var _point_2_x = _corner_pairs[_largest_pair][2]
var _point_2_y = _corner_pairs[_largest_pair][3]
//Find the extension points
var _angle_1 = point_direction(x, y, _point_1_x, _point_1_y)
var _angle_2 = point_direction(x, y, _point_2_x, _point_2_y)
var _middle_angle = _angle_1 + angle_difference(_angle_2, _angle_1) * 0.5
//nudge the outer angles outward to remove shadow gaps
var _nudge_amount = 2
//we only do the nudge if the angle is either very close to horizontal or vertical. It is in those cases we might run into gaps
if abs(cos(degtorad(_angle_1))) < 0.02 or abs(sin(degtorad(_angle_1))) < 0.02{
if _angle_1 > _middle_angle _angle_1 += _nudge_amount else _angle_1 -= _nudge_amount
}
if abs(cos(degtorad(_angle_2))) < 0.02 or abs(sin(degtorad(_angle_2))) < 0.02{
if _angle_2 > _middle_angle _angle_2 += _nudge_amount else _angle_2 -= _nudge_amount
}
//end of nudge
var _ext_point_1_x = x + cos(degtorad(_angle_1)) * light_radius * 2 * tile_size//We multiply by two to make sure our wedge properly covers the shadowed area
var _ext_point_1_y = y - sin(degtorad(_angle_1)) * light_radius * 2 * tile_size
var _ext_point_2_x = x + cos(degtorad(_angle_2)) * light_radius * 2 * tile_size
var _ext_point_2_y = y - sin(degtorad(_angle_2)) * light_radius * 2 * tile_size
var _ext_point_3_x = x + cos(degtorad(_middle_angle)) * light_radius * 2 * tile_size
var _ext_point_3_y = y - sin(degtorad(_middle_angle)) * light_radius * 2 * tile_size
//Draw the triangles
if debug_m {
draw_set_color(c_blue)
draw_circle(_corner_pairs[_largest_pair][0],_corner_pairs[_largest_pair][1], 3, 1)
draw_circle(_corner_pairs[_largest_pair][2],_corner_pairs[_largest_pair][3], 3, 1)
draw_set_color(c_green)
draw_circle(_ext_point_1_x,_ext_point_1_y, 3, 1)
draw_circle(_ext_point_2_x,_ext_point_2_y, 3, 1)
draw_circle(_ext_point_3_x,_ext_point_3_y, 3, 1)
draw_set_color(c_red)
if _draw_closest_corner draw_circle(_closest_corner_x, _closest_corner_y, 3, 1)
draw_set_color(c_yellow)
draw_line(_corner_pairs[_largest_pair][0],_corner_pairs[_largest_pair][1],_ext_point_1_x,_ext_point_1_y)
draw_line(_corner_pairs[_largest_pair][2],_corner_pairs[_largest_pair][3],_ext_point_2_x,_ext_point_2_y)
draw_line(_ext_point_1_x,_ext_point_1_y, _ext_point_3_x, _ext_point_3_y)
draw_line(_ext_point_3_x, _ext_point_3_y,_ext_point_2_x,_ext_point_2_y)
}
//The "opposing pair" are the corners currently not present in the largest pair - we need to use this in a bit if the largest pair form a diagonal in the rectangle
var _opposing_pair = (_largest_pair + 3) mod 6
// make the corner points more readable
var _point_1_x = _corner_pairs[_largest_pair][0]
var _point_1_y = _corner_pairs[_largest_pair][1]
var _point_2_x = _corner_pairs[_largest_pair][2]
var _point_2_y = _corner_pairs[_largest_pair][3]
//Find the extension points
var _angle_1 = point_direction(x, y, _point_1_x, _point_1_y)
var _angle_2 = point_direction(x, y, _point_2_x, _point_2_y)
var _middle_angle = _angle_1 + angle_difference(_angle_2, _angle_1) * 0.5
//nudge the outer angles outward to remove shadow gaps
var _nudge_amount = 2
//we only do the nudge if the angle is either very close to horizontal or vertical. It is in those cases we might run into gaps
if abs(cos(degtorad(_angle_1))) < 0.02 or abs(sin(degtorad(_angle_1))) < 0.02{
if _angle_1 > _middle_angle _angle_1 += _nudge_amount else _angle_1 -= _nudge_amount
}
if abs(cos(degtorad(_angle_2))) < 0.02 or abs(sin(degtorad(_angle_2))) < 0.02{
if _angle_2 > _middle_angle _angle_2 += _nudge_amount else _angle_2 -= _nudge_amount
}
//end of nudge
var _ext_point_1_x = x + cos(degtorad(_angle_1)) * light_radius * 2 * tile_size//We multiply by two to make sure our wedge properly covers the shadowed area
var _ext_point_1_y = y - sin(degtorad(_angle_1)) * light_radius * 2 * tile_size
var _ext_point_2_x = x + cos(degtorad(_angle_2)) * light_radius * 2 * tile_size
var _ext_point_2_y = y - sin(degtorad(_angle_2)) * light_radius * 2 * tile_size
var _ext_point_3_x = x + cos(degtorad(_middle_angle)) * light_radius * 2 * tile_size
var _ext_point_3_y = y - sin(degtorad(_middle_angle)) * light_radius * 2 * tile_size
//Draw the triangles
draw_set_color(c_black)
if debug_m draw_set_alpha(0.2)
draw_primitive_begin(pr_trianglestrip)
if _draw_closest_corner{
draw_vertex(_closest_corner_x,_closest_corner_y )
verts_drawn ++
}
draw_vertex(_point_1_x,_point_1_y)
draw_vertex(_point_2_x,_point_2_y )
draw_vertex(_ext_point_1_x ,_ext_point_1_y)
draw_vertex(_ext_point_2_x ,_ext_point_2_y)
draw_vertex(_ext_point_3_x ,_ext_point_3_y)
verts_drawn += 5
draw_primitive_end()
if debug_m draw_set_alpha(1)
}
}
}
surface_reset_target()
if not debug_m shader_set(sh_360_light)
draw_surface(shadow_surface,floor(x / 256) * 256,floor(y / 224) * 224)
if not debug_m shader_reset()
}
注意: 该代码是基于GameMaker Studio 2的脚本语言。
评论 (0)