Alright, I am having trouble with getting a foolproof way to get the nearest open position for a brick to be placed. This is for an upcoming gamemode I'm working on. Basically, the context is that when the GemProjectile hits, I need it to create a brick at that position, but not overlapping with other bricks. I'll show you my code so far and note it so you know what I am currently doing:
function GemProjectile::OnCollision(%this,%obj,%col,%fade,%pos,%normal)
{
//Check if the collision was a brick and there are gems to pull from
if(%col.getClassName() $= "fxDTSBrick" && UndergroundGemsSO.gemCount > 0)
{
//Just pull random gem data
%gemData = pullGemData(%col.origMineHealth / 4);
%gemColor = pullRandomGemColor();
%angleID = getRandom(0,3);
//Gets the rotation for a specific angleID, I don't know if I even use this
%rotation = $Underground::Rotation[%angleID];
//If the gem pulled was just dirt
if(%gemData $= "Dirt")
{
//Just manually set values for when I create the brick later
%gemDB = brick1x1Data;
%gemColor = "Brown";
%color = 38;
}
else
{
//Actually pull values from the data pulled for the brick I create later
%gemDB = getField(%gemData,1);
%color = getField(%gemColor,1);
}
//This you won't really get as you don't know complete context of code, but if the brick is not cuboid (ex. 1x1 Round Brick) this will be called
//If it isn't cuboid, just bounce it.
if(getField(UndergroundGemsSO.gem[%col.gemType],5) == 1)
{
%obj.bounce(1.0);
return;
}
lilDebug("Normal is now :"@%normal);
//Stole this from fillcan, it sets local variables up to the bricks size and depends on the rotation
//the round function was stolen from fillcan as well
%rot = round(getWord(%rotation,3));
if(%rot == 90 || %rot == 270)
{
%sizeX = %gemDB.brickSizeY;
%sizeY = %gemDB.brickSizeX;
}
else
{
%sizeX = %gemDB.brickSizeX;
%sizeY = %gemDB.brickSizeY;
}
%sizeZ = %gemDB.brickSizeZ;
//Sets up a box of the size of the brick? Don't think I even use this
%box=(%sizeX * 0.5) SPC (%sizeY * 0.5) SPC (%sizeZ * 0.2);
//print the datablock name
lilDebug("%gemDB $= "@%gemDB);
//get the very first position, this would be where the projectile collided.
lilDebug("%pos first == "@%pos);
//I check the normal that I either got from the function or from what I set up if the collision was not cuboid
//And set up %scale so that I can push the brick away from the collided brick appropriately
if(getWord(%normal,0) == "1" || getWord(%normal,0) == "-1")
{
%scale = %sizeY * 0.25;
}
else if(getWord(%normal,1) == 1 || getWord(%normal,1) == "-1")
{
%scale = %sizeX * 0.25;
}
else if(getWord(%normal,2) == 1 || getWord(%normal,2) == "-1")
{
%scale = %sizeZ * 0.1;
}
//Actually scale the vector and add it to the original position so I get a position that would be open if the collision brick was the only existing brick
%vector = vectorScale(%normal,%scale);
lilDebug("Took %normal ("@%normal@") scaled it by %scale ("@%scale@") to get %vector ("@%vector@")");
lilDebug("Took %pos ("@%pos@") and added vector ("@%vector@")");
//I added the normal here, I will refer to this position a lot from here on and will refer to it as the "Gem Position"
%pos = vectorAdd(%pos,%vector);
lilDebug("Now we have %pos == "@%pos);
//Here is where it gets tricky/messy
//I attempt to check all 6 directions relative to the "open" position I get in search of any overlapping bricks
//First check is to see if there is a brick above the position.
//I will show the getBrickAtPos function separately
//But basically the first argument is the position to check, and the second argument is a box around the position to check in
//So I don't really want to check a full box of the brick so that I only get bricks that are above the position
//vectorAdd(%pos,"0 0" SPC %sizeZ * 0.18) should return a position that is just under where the top of brick should be
//%sizeX * 0.24 SPC %sizeY * 0.24 SPC "0" should be a box size that is really just a horizontal plane that would fit within the "brick"
if(%lapBrick = getBrickAtPos(vectorAdd(%pos,"0 0" SPC %sizeZ * 0.18),%sizeX * 0.24 SPC %sizeY * 0.24 SPC "0"))
{
lilDebug("Brick at positive z axis"SPC %lapBrick);
//I get the brickSizeZ of the found brick
%sizeZ2 = %lapBrick.getDatablock().brickSizeZ * 0.1;
%totalAdd = %sizeZ2 + %sizeZ * 0.1;
//Get the half sizes of both bricks, add them, and then add that to the %lapBricks position to push it away just enough
lilDebug("%sizeZ2 $= "@%sizeZ2@" and adding" SPC %sizeZ * 0.1@" for "@%totalAdd);
%makeShiftPos = getWords(%pos,0,1) SPC getWord(%lapBrick.getPosition(),2);
%pos = vectorAdd(%makeShiftPos,"0 0" SPC %totalAdd);
//Here I create a make-shift position that would be the x and y of the Gem Position and the z position of the found brick
%makeShiftPos = getWords(%pos,0,1) SPC getWord(%lapBrick.getPosition(),3);
//Set the gem position to the make-shift pos, but added %newZ, it's hard to explain this without visually showing you
%pos = vectorSub(%makeShiftPos,"0 0" SPC %newZ);
lilDebug("Moved brick along z-axis to "@%pos);
}
//I do the same thing as above for all 6 direction, but with different values for positive/negative x/y/z positions. I don't really want to repeat myself right now.
if(%lapBrick = getBrickAtPos(vectorAdd(%pos,"0 0" SPC -%sizeZ * 0.18),%sizeX * 0.24 SPC %sizeY * 0.24 SPC "0"))
{
lilDebug("Brick at negative z axis"SPC %lapBrick);
%sizeZ2 = %lapBrick.getDatablock().brickSizeZ * 0.1;
%totalAdd = %sizeZ2 + %sizeZ * 0.1;
lilDebug("%sizeZ2 $= "@%sizeZ2@" and adding" SPC %sizeZ * 0.1@" for "@%totalAdd);
%makeShiftPos = getWords(%pos,0,1) SPC getWord(%lapBrick.getPosition(),2);
%pos = vectorAdd(%makeShiftPos,"0 0" SPC %totalAdd);
lilDebug("Moved brick along z-axis to "@%pos);
}
if(%lapBrick = getBrickAtPos(vectorAdd(%pos,%sizeX * 0.24 SPC "0 0"),"0" SPC %sizeY * 0.24 SPC %sizeZ * 0.18))
{
lilDebug("Brick at positive x axis"SPC %lapBrick);
%sizeX2 = %lapBrick.getDatablock().brickSizeX * 0.25;
%totalAdd = %sizeX2 + %sizeX * 0.25;
lilDebug("%sizeX2 $= "@%sizeX2@" and adding" SPC %sizeX * 0.25@" for "@%totalAdd);
%makeShiftPos = getWord(%lapBrick.getPosition(),0) SPC getWords(%pos,1,2);
%pos = vectorSub(%makeShiftPos,%totalAdd SPC "0 0");
lilDebug("Moved brick along x-axis to "@%pos);
}
if(%lapBrick = getBrickAtPos(vectorAdd(%pos,-%sizeX * 0.24 SPC "0 0"),"0" SPC %sizeY * 0.24 SPC %sizeZ * 0.18))
{
lilDebug("Brick at negative x axis"SPC %lapBrick);
%sizeX2 = %lapBrick.getDatablock().brickSizeX * 0.25;
%totalAdd = %sizeX2 + %sizeX * 0.25;
lilDebug("%sizeX2 $= "@%sizeX2@" and adding" SPC %sizeX * 0.25@" for "@%totalAdd);
%makeShiftPos = getWord(%lapBrick.getPosition(),0) SPC getWords(%pos,1,2);
%pos = vectorAdd(%makeShiftPos,%totalAdd SPC "0 0");
lilDebug("Moved brick along x-axis to "@%pos);
}
if(%lapBrick = getBrickAtPos(vectorAdd(%pos,"0" SPC %sizeY * 0.24 SPC "0"),%sizeX * 0.24 SPC "0" SPC %sizeZ * 0.18))
{
lilDebug("Brick at positive y axis"SPC %lapBrick);
%sizeY2 = %lapBrick.getDatablock().brickSizeY * 0.25;
%totalAdd = %sizeY2 + %sizeY * 0.25;
lilDebug("%sizeY2 $= "@%sizeY2@" and adding" SPC %sizeY * 0.25@" for "@%totalAdd);
%makeShiftPos = getWord(%pos,0) SPC getWord(%lapBrick.getPosition(),1) SPC getWord(%pos,2);
%pos = vectorSub(%makeShiftPos,"0" SPC %totalAdd SPC "0");
lilDebug("Moved brick along y-axis to "@%pos);
}
if(%lapBrick = getBrickAtPos(vectorAdd(%pos,"0" SPC -%sizeY * 0.24 SPC "0"),%sizeX * 0.24 SPC "0" SPC %sizeZ * 0.18))
{
lilDebug("Brick at negative y axis"SPC %lapBrick);
%sizeY2 = %lapBrick.getDatablock().brickSizeY * 0.25;
%totalAdd = %sizeY2 + %sizeY * 0.25;
lilDebug("%sizeY2 $= "@%sizeY2@" and adding" SPC %sizeY * 0.25@" for "@%totalAdd);
%makeShiftPos = getWord(%pos,0) SPC getWord(%lapBrick.getPosition(),1) SPC getWord(%pos,2);
%pos = vectorAdd(%makeShiftPos,"0" SPC %totalAdd SPC "0");
lilDebug("Moved brick along y-axis to "@%pos);
}
//I finally create the brick with the datablock pulled at the beginning, at the newly created pos, with the previously pulled color.
%newBrick = newBrick(%gemDB,%pos,1,%color);
//I just set values pertaining to the mod if the brick is actually created, and delete it 20 seconds later to avoid clutter
if(isObject(%newBrick))
{
%newBrick.gemType = getField(%gemData,0);
%newBrick.gemColor = getField(%gemColor,0);
%newBrick.gemName = %newBrick.gemColor SPC %newBrick.gemType;
%newBrick.schedule(20000,delete);
}
//Kill the projectile, don't want it just sitting there, but I think there's a value for this in the projectile datablock...
%obj.delete();
}
}
Here is the getBrickAtPos function
function getBrickAtPos(%pos,%box,%offset)
{
%offset = %offset $= "" ? 0 : %offset;
InitContainerBoxSearch(%pos,%box,$TypeMasks::fxBrickObjectType);
for(%i=0;%i<=%offset;%i++)
{
%obj = containerSearchNext();
}
if(isObject(%obj))
{
return %obj;
}
else
{
return 0;
}
}
I know this code seems slightly intimidating, but I could really use some help here. The problem is that sometimes it creates bricks at random spots nearby, not where they should be. I ultimately just need a way to get the open position, if you know a way that's completely different to this, please let me know, I'm fine with scratching this code. Any help is better than none.
Also, if you have any questions at all with what I'm trying to do at some part, ask away.