You are not logged in.
This is more of a theory or solution question than pertaining to actual code (as my code works as well as I can get it to work right now, anyway). Also, I am working in GM7 (my project did not like being ported to 8... so I stuck with 7)
I am fairly new to surfaces, but I really enjoy how they work so far. Let me explain what I have going on.
I have a mask that creates a day night cycle in my 2D game. The mask is constantly drawing a square to a surface the size of the view with a ever shifting color based on the time of day. I then display the surface with the blend modes set to emulate "multiply" in photoshop.
Begin Step event in mask Object:
The mask does this in it's "begin step". This allows other objects to draw to this same surface before the mask object draws it to the screen in it's draw event. In this manner, I layer shapes on top of shapes within the same surface to emulate lighting.
So, I have a light object in my room that in it's step event draws a circle that is one color on the inside and then the outside matches the same color as the background of the surface. (see below) Then, in the light's end step event, it draws a solid circle that matches the inside color. This gives my light a specified area of solid color, surrounded by a gradient that blends to the surface background. When all is said and done, it's a pretty convincing effect.
Step Event:
End Step Event:
Effect In Action:
However, a problem occurs when two lights intersect.
Problem one occurs when drawing the smooth circle in the step event. When two circles drawn this way intersect, the one drawn last overwrites the previous one, breaking the illusion.
The second problem occurs when the lights are different colors. Again, the one drawn last overwrites the previous one.
The above issue is exacerbated by the fact that the "blend area" around the edges of the light are constantly shifting randomly to create a "flicker" effect. Again, by itself it is very convincing, but when intersecting with other lights, the illusion breakage is jarring.
So, here are my questions.
1) I believe I could work around both issues with level and game design, however to do so I would need to be able to control which lights get drawn first. Is there any way to control which order objects get updated?
2) Obviously the best fix would to make all of these shapes and gradients I am drawing blend with one another... is there any possible way of doing that (without totally hosing my performance)?
Thanks for your time in advance.
Last edited by Pixelated_Pope (2010-04-27 11:36:38)
Offline
Since light is an additive phenomenon, draw all of your lights onto a black shading surface with an additive blend mode. Then draw that using a multiplicative blend over your already drawn background.
Abusing forum power since 1986.
Offline
I will give that a try and then post the results. Thanks, Xot.
Offline
Okay, so I think this could actually work really well, but I need to be able to combine the light overlay with the "time of day" overlay without it drawing to the screen... Problem is, I've ran out of "steps".
Begin Step: Draw the Black Rectangle for the light surface and the colored rectangle for the timeofday surface.
Step: In all of the light objects - draw the soft graduated lights.
End Step: In all of the light objects - draw the solid circles of absolute light.
?? Step: Combine the light surface with the time of day surface.
Draw Step: Draw the time of day surface.
Is there any way I can guarantee that something will happen after the end step but before drawing? Trying to combine the two surfaces in the draw event right before drawing occurs looks very very very messed up. Alternatively, is there anyway to do something in the draw even (like drawing a surface to another surface) without it being displayed on screen?
Offline
You can do it all in one step, can't you?
I don't understand the need to separate anything, or to draw two kinds of light effects separately. I don't know what a "time of day" overlay is.
It is not possible to draw to a surface during the draw event, although you might be able to use surface_copy. Since it copies surface data directly blend modes won't work with it.
A single step approach:
1. Set render target to light surface.
2. Clear to black.
3. Set blend mode to (bm_one,bm_one) (additive)
4. with (light objects) { draw the soft graduated lights }
5. with (light objects) { draw the solid circles of absolute light }
6. Set blend mode to (bm_dest_color,bm_zero) (multiplicative)???
7. Draw timeofday surface???
8. Set blend mode back to normal.
9. Reset render target.
Abusing forum power since 1986.
Offline
Hmm... Wow. Yeah, I guess that makes sense. lol. I'll have to give that a shot and report back.
Offline
Got it all in and working great. I seem to always over complicate things. Thanks, Xot.
Offline
Cool! Glad to help.
Abusing forum power since 1986.
Offline
Actually... while I've got your attention, can I point you at another question I posted on the yoyogames forums?
http://gmc.yoyogames.com/index.php?showtopic=472035
I've used the method suggested by the one person who responded... and it looks awesome for when the player is standing in water... but it looks less awesome when standing in grass. Any suggestions on how I could produce the same effect seen in those screenshots?
Offline
My only idea is if there is a way to detect when the player is touching a grass tile, to have the player object draw a grass sprite on top of itself.
Abusing forum power since 1986.
Offline
I can detect whether the player is on a grass tile (they are on their own tile layer. So if there is a tile at depth X at player.x player.y then do something) but simply drawing a grass sprite on top of them doesn't really work. The reason being, as the player moves around on the grass, the grass would be moving with the player... and that is not exactly a convincing illusion. I even tried an effect where when a player was on a grass tile, the tile's depth would be changed to be on top of the player. The problem that caused is as the player is walking from one tile to the next, during the transition, up to half of the character wouldn't be covered in grass... not very pleasing on the eye.
The ideal solution in my mind would be if I could some how take a portion of the tile layer around the player's feet and draw it as a sprite on top of the player. But I can't find any way to isolate a specific tile depth to to capture as a sprite for redrawing...
Hmm... I did just have another idea... let me go try that...
Offline
Well, I came up with a good idea... it involves using draw_sprite_part_ext which is really hard to use when you are flipping the x scale of your sprites constantly... So I couldn't get the bottom half of my sprite to line up perfectly with the top half. But essentially what I was doing was creating a clone object that would draw the player's sprite at a depth below the grass, and then I would hide the bottom half of the player's sprite. I got it to line up for one player, but a player of a different size didn't work (apparently the calculations weren't as universal as I had hoped). I'm going to give up on this for now... it's not really worth the time I've already spent on it.
Thanks for your help again.
Offline