Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic lights on objects #12

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,57 @@ Hallowflame and the empty AM template come with the base cast pre-set!

Feel free to reach out and suggest additional options!

### Glowing Objects
You can configure your character, their projectiles, their articles, or any other object to glow in dark areas. Adding dynamic lights to your objects requires a little bit of setup, but you'll only have to do it once. Just put these two lines into your `init.gml` file:

```gml
dynamic_lights = undefined;
with(obj_stage_main) if("dynamic_lights" in self) other.dynamic_lights = dynamic_lights;
```

Now you can make any object you'd like glow when your character is in an Adventure Mode stage that supports dynamic lighting. For instance, to make Sandbert's NSpecial glow, you could put this in his `hitbox_create.gml` file:

```gml
if(attack == AT_NSPECIAL) {
if(player_id.dynamic_lights != undefined) ds_list_add(player_id.dynamic_lights, {
on_instance: id,
burnout_speed: 0.15,
darkness_threshold: 200,
sprite: sprite_get("glow"),
image: 0,
x: x,
y: y,
xscale: 1,
yscale: 1,
x_offset: 0,
y_offset: 0,
angle: 0,
blend: c_pink,
alpha: 0.6,
});
}
```

All of these values are required or you'll end up with errors. Here are what they all do:

```
on_instance - The Instance ID of the object this light source is attached to.
burnout_speed - How fast the light goes out when the object it's attached to disappears. Higher values disappear faster.
darkness_threshold - How dark a room's ambient lighting has to be before the object will glow. Ranges from 1 (only glows in complete darkness) to 256 (always glows).
sprite - The sprite that the glow will use. Generally this should be a circular gradient. The strength of the glow is affected by the Alpha channel of each pixel.
image - Which subimage to use of the sprite.
x & y - The position that the glow will be at on its first frame.
xscale & yscale - The visual size of the glow.
x_offset & y_offset - The glow will be automatically placed at the on_instance object's position, offset with these variables' values.
angle - The angle at which the glow sprite displays. More useful for something like a flashlight, as opposed to a typical round glow.
blend - The image_blend that will be applied to the glow sprite. Keep in mind that colour blending can only make an image darker, not lighter.
alpha - How transparent the glow will be. Lower values make the glow fainter. Ranges from 0 (no glow) to 1 (maximum glow).
```

Once all of these are applied, you're done! The stage will automatically handle moving the light around, keeping the list clean, etc.

If you're familiar with manipulating Lightweight Objects, also known as Structs, that's all these are. You can save the index of the LWO before passing it into the `dynamic_lights` list if you'd like to modify it later. Doing so can allow you to change any of its properties. Changing the glow's `on_instance` to `noone` is a good way to make it fizzle out immediately.

## Optimization Strategies

The RoAAM team will continue to do our best optimizing the engine over time, however as stated in Limitations there is a lot of overhead to account for, and the mod will not run well on lower end computers. Here are a list of optimization strategies figured out during the development of Hallowflame to help lift the computational burden.
Expand Down
14 changes: 14 additions & 0 deletions scripts/article12_draw.gml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ if(!cant_root && draw)
draw = false;
}
}
var i = 0, drawing_light;
repeat ds_list_size(player_id.dynamic_lights) {
drawing_light = player_id.dynamic_lights[| i];
if(colour_get_value(bg_color_true) < drawing_light.darkness_threshold)
draw_sprite_ext(drawing_light.sprite, drawing_light.image, drawing_light.x, drawing_light.y, drawing_light.xscale, drawing_light.yscale, drawing_light.angle, drawing_light.blend, drawing_light.alpha);
i++;
}
gpu_set_blendenable(true);
gpu_set_alphatestenable(true);
gpu_set_colorwriteenable(true,true,true,true);
Expand All @@ -31,6 +38,13 @@ if(!cant_root && draw)
//if val_limit < color_get_value(other.bg_color_true) draw_sprite_ext(render_sprite, render_index, x, y, image_xscale, image_yscale, image_angle, c_white, 1);
}
}
i = 0;
repeat ds_list_size(player_id.dynamic_lights) {
drawing_light = player_id.dynamic_lights[| i];
if(colour_get_value(bg_color_true) < drawing_light.darkness_threshold)
draw_sprite_ext(drawing_light.sprite, drawing_light.image, drawing_light.x, drawing_light.y, drawing_light.xscale, drawing_light.yscale, drawing_light.angle, drawing_light.blend, drawing_light.alpha);
i++;
}
gpu_set_blendmode(bm_normal);
gpu_set_alphatestenable(false);
draw_set_alpha(1);
Expand Down
1 change: 1 addition & 0 deletions scripts/init.gml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ cam_vel_influence = 20;
game_paused = false;
counter = 0;

dynamic_lights = ds_list_create();

debug_console = false;
debug_x = 650;
Expand Down
1 change: 1 addition & 0 deletions scripts/load.gml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ sprite_change_offset("well",24, 70);
sprite_change_offset("light", 39, 46);
sprite_change_offset("light_dimver", 40, 49);
sprite_change_offset("light_dimver_larg", 40*4, 49*3+25);
sprite_change_offset("light_sein", 40*4, 49*3+25);
sprite_change_offset("enemy_10_vision", 0, 84);
sprite_change_offset("house_main_inside",15, 111);
sprite_change_offset("house_main_insideb",15, 111);
Expand Down
66 changes: 65 additions & 1 deletion scripts/other_init.gml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ switch p_name {
// am_is_clothed = false; LOINCLOTH
am_is_guest = false;
pronouns = ["he","him","his","is"];

//Zetterburn glows
with(obj_stage_main) ds_list_add(dynamic_lights, {
on_instance: other,
burnout_speed: 0.15,
darkness_threshold: 200,
sprite: sprite_get("light"),
image: 0,
x: x,
y: y,
xscale: 2,
yscale: 2,
x_offset: 0,
y_offset: -30,
angle: 0,
blend: c_red,
alpha: 0.6,
});
break;
//Bastard turned good boi
case "Forsburn":
Expand All @@ -104,6 +122,28 @@ switch p_name {
// am_is_experienced = true;
am_is_guest = false;
pronouns = ["he","him","his","is"];

//Forsburn glows, but only when he's not emitting smoke
dynamic_glow = {
on_instance: id,
burnout_speed: 0.15,
darkness_threshold: 170,
sprite: asset_get("empty_sprite"),
image: 0,
x: x,
y: y,
xscale: 1.6,
yscale: 1.6,
x_offset: 0,
y_offset: -30,
angle: 0,
blend: c_orange,
alpha: 0.3,
};
with(obj_stage_main) {
other.dynamic_glow.sprite = sprite_get("light"); //give Forsburn the sprite index (he can't use sprite_get)
ds_list_add(dynamic_lights, other.dynamic_glow);
}
break;
//Protagonist Prime
case "Clairen":
Expand Down Expand Up @@ -241,13 +281,37 @@ switch p_name {
pronouns = ["she","her","hers","is"];
break;
//Upair is a kill move
case "Ori":
case "Ori & Sein":
am_is_aether = true;
am_is_verbal = false;
am_is_magic = true;
am_is_small = true; //Cannon Ori is tiny
am_is_experienced = true;
//They are a leaf and I don't think we get cannonical pronouns

//Sein glows (i think??)
var sein_id = id;
with(asset_get("orb_obj")) sein_id = self;
dynamic_glow = {
on_instance: sein_id,
burnout_speed: 0.15,
darkness_threshold: 245,
sprite: asset_get("empty_sprite"),
image: 0,
x: x,
y: y,
xscale: 0.75,
yscale: 0.75,
x_offset: 0,
y_offset: 15,
angle: 0,
blend: c_white,
alpha: 0.2,
};
with(obj_stage_main) {
other.dynamic_glow.sprite = sprite_get("light_sein"); //give Ori the sprite index
ds_list_add(dynamic_lights, other.dynamic_glow);
}
break;
//????
case "Shovel Knight":
Expand Down
46 changes: 45 additions & 1 deletion scripts/update.gml
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,60 @@ if !_init {
// if state != PS_AIR_DODGE old_pos = [x,y];

// if state == PS_RESPAWN print("[update:player] completed check");

if(url == CH_FORSBURN) {
if(spewing_smoke) {
dynamic_glow.xscale *= 0.8;
dynamic_glow.yscale *= 0.8;
}
else {
dynamic_glow.xscale = 1.6;
dynamic_glow.yscale = 1.6;
}
}
else if(url == CH_ORI) {
if((state == PS_ATTACK_GROUND || state == PS_ATTACK_AIR) && (attack == 20 || attack == 21 || attack == 22))
dynamic_glow.on_instance = id; //Sein's glow comes from Ori's position when using a team-up attack
else if dynamic_glow.on_instance == id with(asset_get("orb_obj")) {
other.dynamic_glow.on_instance = self;
}
}
}


var i = 0;

repeat ds_list_size(active_bosses) {
if (!instance_exists(active_bosses[| i]))
ds_list_remove(active_bosses,active_bosses[| i]);
i++;
}
i = 0;
repeat ds_list_size(dynamic_lights) {
if (!instance_exists(dynamic_lights[| i].on_instance)) {
if(dynamic_lights[| i].burnout_speed != undefined) {
//initialize burning out
dynamic_lights[| i].burnout_sign = -1 * sign(dynamic_lights[| i].xscale);
dynamic_lights[| i].burnout_xspeed = dynamic_lights[| i].burnout_sign * dynamic_lights[| i].burnout_speed;
dynamic_lights[| i].height_ratio = dynamic_lights[| i].yscale / dynamic_lights[| i].xscale;
dynamic_lights[| i].burnout_speed = undefined;
}
dynamic_lights[| i].xscale += dynamic_lights[| i].burnout_xspeed;
dynamic_lights[| i].yscale = dynamic_lights[| i].height_ratio * dynamic_lights[| i].xscale;

// dynamic_lights[| i].alpha -= 2 * sign(dynamic_lights[| i].burnout_xspeed);

if(sign(dynamic_lights[| i].xscale) == dynamic_lights[| i].burnout_sign) {
ds_list_remove(dynamic_lights,dynamic_lights[| i]);
i--;
}
}
else {
dynamic_lights[| i].x = get_instance_x(dynamic_lights[| i].on_instance) + dynamic_lights[| i].x_offset;
dynamic_lights[| i].y = get_instance_y(dynamic_lights[| i].on_instance) + dynamic_lights[| i].y_offset;
}
i++;
}

//Window Update Call
win_call = 2;
user_event(2);
Expand Down
Binary file added sprites/articles/light_sein_strip4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.