Best way to stamp() over a FlxTilemap?



  • Hello!

    I'm trying to optimize the way I spawn decals in my world.

    Basically, what I'm doing now is having a transparent rectangle, which I call stamp() on. This produces a result like this:

    alt text

    However, setting up those rectangles can be tiresome:

    alt text

    Is there a way to properly do this? Any info would be super appreciated!



  • Is the spawning of blood only supposed to happen proximate to the player?

    If so, you could have an array of these rectangles set up, upon the death event, get all rectangles within a certain distance from the player and stamp them.

    If you're trying to avoid using predetermined locations on the map to stamp sprites, you could have a transparent rectangle follow the player's x and y, and then stamp that on the death event.

    What exactly are you trying to implement with these effects?



  • Basically, blood happens all around entities, both players and npcs.

    I've got the decals working actually. I just would like to find a more efficient method to have decals.

    Check this image for reference:

    alt text

    There's a few implemented method of decals:

    • Blood
    • Grenade scorch
    • Bullets

    The blood one comes in two types:

    1 - Big one: calls stamp() using a position around mid point of the player or npc.
    2 - Small one: a moving FlxParticle that calls stamp() while is touching the ground.

    Is nothing really fancy, here's what I do:

    public function placeDecal(X:Float, Y:Float, type:Int = 0 ):Void
    	{
    		blood_collision.forEach(function(spr:FlxSprite)
    		{
    			if (Registry.IS_SURVIVAL)
    			{
    				bloodSprite.alpha = FlxG.random.float(0.5, 1);
    				bloodSprite2.alpha = FlxG.random.float(0.1, 1);
    				
    				var randomScale:Float = FlxG.random.float(0.5, 1);
    				var randomAngle:Float = FlxG.random.float(0, 360);
    				
    				bloodSprite.scale.set(randomScale, randomScale);
    				bloodSprite2.scale.set(randomScale, randomScale);
    				
    				bloodSprite.angle = randomAngle;
    			//	bloodSprite2.angle = randomAngle;
    				
    				bloodSprite.antialiasing = true;
    				bloodSprite2.antialiasing = true;
    			}
    		
    			if (type == 0)//blood
    			{
    				if(FlxG.random.bool())
    				spr.stamp( bloodSprite, Std.int(X - spr.x - bloodSprite.width / 2), Std.int(Y - spr.y - bloodSprite.height / 2) );
    				else
    				spr.stamp( bloodSprite2, Std.int(X - spr.x - bloodSprite2.width / 2), Std.int(Y - spr.y - bloodSprite2.height / 2) );
    			}
    			else if(type == 1)
    			spr.stamp( bulletHoleSprite, Std.int(X - spr.x - bulletHoleSprite.width / 2), Std.int(Y - spr.y - bulletHoleSprite.height / 2) );
    			else if(type == 2)
    			spr.stamp( bloodSmallSprite, Std.int(X - spr.x - bloodSmallSprite.width / 2), Std.int(Y - spr.y - bloodSmallSprite.height / 2) );
    			else if(type == 3)
    			spr.stamp( decalScorch, Std.int(X - spr.x - decalScorch.width / 2), Std.int(Y - spr.y - decalScorch.height / 2) );
    		});	
    	}
    

    If so, you could have an array of these rectangles set up, upon the death event, get all rectangles within a certain distance from the player and stamp them.

    I've got the rectangles, but I have to set them manually. Your method would actually work really well if the maps were simple. I've got corners, holes, complex scenery. Coding the position and dimensions of such rectangles, dynamically, could be really hard to implement.

    I'd like to know if theres something like, for example:

    • A method to have FlxTilemap.graphics as a sprite you can call stamp() on.
    • A method to use masking, somehow, using the tilemap as reference.

    Or perhaps a out of the box method. Not really sure :(



  • I'm trying to understand the limitations you are imposing on yourself.
    Are you worried about the blood extending beyond the corner, tile, or hole - is the purpose of the rectangles to 'mask' the stamps?

    How are you creating the tilemap?

    One suggestion I might have is to define a 'type' of tile that receives blood splatters.

    When the tilemap is created/loaded, store the x/y of each tile as an FlxPoint in a Haxe.ds.Vector or just a plain old array.

    Upon a death event, sort all the values in the previous array according to their proximity to the player.

    Use array indexes closest to the death event to stamp blood at the stored x/y.

    Not a great solution however, as then you have to test whether one tile is 'beneath' another tile, maybe with raycasting.

    In fact, you might be able to use a few rays to get all the appropiate tiles. Then you can stamp away.

    Not sure what to do about the masking, unless you want to spawn a mask first, and then stamp.

    To be honest, if your maps are not procedurally generated, you may simply be forced to put a labor of love into the map design and place all the rectangles manually.

    I understand why you would rather not do that. However, the way you're implementing blood splatters may in itself be problematic. Sometimes when I hit problems like this where it feels like im doing a lot of awkard 'fixes' for a cheap effect, I scale backward and ask myself if there isn't a simpler, better way to achieve something. Even if it means tweaking some aspects of gameplays/aesthetics.



  • You bring up some interesting questions.

    The tilemap is just a FlxTilemapExt. Nothing fancy there.

    I could grab tiles nearby entities. What I wonder is how the stamp would work. Not sure if there's a way to get the sprite of any given tilemap ? Plus, as you correctly pointed out, I'm afraid that the stamping would go outside the boundaries of said tiles. And yes, this is the purpose of the rectangles, to mask the stamps.

    I might place all those rectangles manually, but sounds like a brute forced solution. I was wondering how other people might solve this, but sounds like isn't a easy task. Many thanks @jcox171 for your replies so far :)


Log in to reply
 

Looks like your connection to HaxeFlixel was lost, please wait while we try to reconnect.