How would I detect if a player is looking at another entity? - bukkit

I have a player and of course able to grab the direction the player is facing in vector form.
Using this vector, I need to calculate if the player is looking at an entity within x blocks and if a 'spell' would hit it. I would also need to take in account if there is anything in front of the entity.
So far my thought process has been to first, get a list of all entities in x blocks of the player. But from there, I have no clue.
Any help leading me in the right direction would be awesome.

I edited your code to be more precise and less complicated, it doesn't go through blocks. But your method is fine to :D
public static Entity getNearestEntityInSight(Player player, int range) {
ArrayList<Entity> entities = (ArrayList<Entity>) player.getNearbyEntities(range, range, range);
ArrayList<Block> sightBlock = (ArrayList<Block>) player.getLineOfSight( (Set<Material>) null, range);
ArrayList<Location> sight = new ArrayList<Location>();
for (int i = 0;i<sightBlock.size();i++)
sight.add(sightBlock.get(i).getLocation());
for (int i = 0;i<sight.size();i++) {
for (int k = 0;k<entities.size();k++) {
if (Math.abs(entities.get(k).getLocation().getX()-sight.get(i).getX())<1.3) {
if (Math.abs(entities.get(k).getLocation().getY()-sight.get(i).getY())<1.5) {
if (Math.abs(entities.get(k).getLocation().getZ()-sight.get(i).getZ())<1.3) {
return entities.get(k);
}
}
}
}
}
return null; //Return null/nothing if no entity was found
}

Your thought process of getting all the entities within a certain range of the player is a good start in my opinion! Below is an example of a method that uses the blocks in a player's line of sight (raytrace) to find the nearest entity that isn't obstructed.
public static Entity getNearestEntityInSight(Player player, int range) {
List<Entity> entities = player.getNearbyEntities(range, range, range); //Get the entities within range
Iterator<Entity> iterator = entities.iterator(); //Create an iterator
while (iterator.hasNext()) {
Entity next = iterator.next(); //Get the next entity in the iterator
if (!(next instanceof LivingEntity) || next == player) { //If the entity is not a living entity or the player itself, remove it from the list
iterator.remove();
}
}
List<Block> sight = player.getLineOfSight((Set) null, range); //Get the blocks in the player's line of sight (the Set is null to not ignore any blocks)
for (Block block : sight) { //For each block in the list
if (block.getType() != Material.AIR) { //If the block is not air -> obstruction reached, exit loop/seach
break;
}
Location low = block.getLocation(); //Lower corner of the block
Location high = low.clone().add(1, 1, 1); //Higher corner of the block
AxisAlignedBB blockBoundingBox = AxisAlignedBB.a(low.getX(), low.getY(), low.getZ(), high.getX(), high.getY(), high.getZ()); //The bounding or collision box of the block
for (Entity entity : entities) { //For every living entity in the player's range
//If the entity is truly close enough and the bounding box of the block (1x1x1 box) intersects with the entity's bounding box, return it
if (entity.getLocation().distance(player.getEyeLocation()) <= range && ((CraftEntity) entity).getHandle().getBoundingBox().b(blockBoundingBox)) {
return entity;
}
}
}
return null; //Return null/nothing if no entity was found
}
Note: There are a few things/potential bugs to consider when using the method above:
The way the check whether the block's bounding box intersects with the entity's bounding box works means that the player might not actually be looking directly at the entity but only at part of the block. This proximity check can be done in a variety of different ways (for example: Checking whether the entity location is near the block's location) but most are not necessarily more precise. To get a more accurate result you'd need to make your own ray trace that scans smaller distances to make sure it doesn't "miss" any entities and to check whether the player is truly looking directly at the entity. The more precise you want it to be the more resources/time it will take. Check to see if this method is precise enough for you.
The loop that looks through the nearby entities chooses the first one it finds that meets the criteria, meaning that if two or three entities are bunched up and close together, it might not choose the "true" closest one (this could be fixed with more checks though and might not be that important).
The check whether an entity is obstructed only looks for blocks that are not air and therefore doesn't consider transparent blocks or blocks with small collision boxes (e.g. Looking through some stairs might return null even though you might technically be able to see the entity). Once again, this doesn't make a big difference usually and I think correcting it is rather tricky.

Related

Backtracking algorithm for cell connections in a grid

The explanation might be confusing or long (or both), so please let me know if there needs to be any clarification.
I am currently designing a backtracking algorithm to find a solution for something similar to what a game of "snake" looks like.
The program will start with a 2D grid, where some of the cells are inaccessible (like an obstacle). The program then proceeds with a backtracking algorithm to connect int x sequence of cells into a string-like group, then repeats this process until all int y accessible cells in the grid are connected into y / x groups. There are no cases where y is indivisible by x.
To determine the cost of the group, there are certain priority on the direction of the connection. For simplification, I will only use 3 connection types, double horizontal, double vertical, and double diagonal, where horizontal has the lowest cost and diagonal has the highest.
I've spent numerous days on trying to come up with different backtracking algorithms, but none of them had worked so far.
Here's a rough sketch of what I have(actual code has lots of custom class involved, so it may cause a lot of confusions):
String_c Grid::backtracking(int x, int y, int tot_pnl_needed, String_c &str_orig){
bool branch_found = false;
String_c str_cur = str_orig;
// set cell (x,y) as occupied. OCCUPIED is an enum value
set_avail(x,y,OCCUPIED);
str_cur.push_cell(x,y);
if (str_cur.is_complete()) {
return str_cur;
}
String_c str_tmp;
std::priority_queue<String_c, std::vector<String_c>, compareString> queue;
// if the neighboring cell is available, create a branch
if (is_available(x+1, y)){ // right side
tmp_str = backtracking(x+1, y, tot_pnl_needed-1, str_cur);
if (tmp_str == failed){ // assume that "failed" is a special String_c object. == operator is overloaded.
set_avail(x+1,y,AVAILABLE); // AVAIL is an enum value
tmp_str.pop_cell();
}
else{
branch_found = true;
queue.push(&tmp_str);
}
}
// copy this selection code above for each different direction
if (branch_found) {
while (!queue.empty()) {
// push all branches into the stack, which is a parameter of Grid class
stack.push(queue.pop());
}
else return failed;
return stack.top();
This is a pseudo code for the minimum backtracking algorithm required. In actual program, if the algorithm hits branch_found == false at the end, it needs to flip the sequence of the String_c, then continue the backtracking until it finds no branch again. Again, after one backtracking algorithm is finished, it will be called again until all cells are occupied.
One thing to be noted is that even if a String_c is completed and is pushed to the stack, it may be reverted later if none of its branch had found a solution.
This is the first time attempting to program a backtracking algorithm, so it was really stressful even to come up with this (which still fails...)
If you are the expert at this matter, I would greatly appreciate your help.

Using glutTimerFunc with glutMouseFunc

I am trying to do a little game, and in my game I have some squares and when the user click on these squares, they got highlighted. To achieve this effect I am using glutMouseFunc with glutTimerFunc.
When the user clicks on the screen I pick the pixel and identify the square I need to highlight. Once the square is identified I call glutTimerFunc. The function registred with glutTimerFunc increase the value of each component of color by 0.01 until they reach one max value defined by me, then this value goes back to a minimum value.
glutTimerFunc execute in 60 milliseconds and I get a almost smooth shine effect.
My problem is, if I click on two squares very fast, the effect starts on the first square, but don't finish, so the square remains highlighted and the second squares do the entire effect. If I click like a crazy man on every square, all of them got highlighted.
How can I make this effect of shining terminate even if I click on other square?
Here is a snippet of code
void Memoria::shineEffect(GLint value) {
if(value == 1) {
for(GLint i = 0; i < 3; i++) {
if(colors[selectedSquare][i] > 0) {
colors[selectedSquare][i] += COLOR_INCREASE;
if(colors[selectedSquare][i] >= MAX) {
colors[selectedSquare][i] = MAX;
value = -1;
}
}
}
glutTimerFunc(FPS, timeWrapper, value);
}
else {
if(value == -1) {
for(GLint i = 0; i < 3; i++) {
if(colors[selectedSquare][i] > 0) {
colors[selectedSquare][i] -= COLOR_INCREASE;
if(colors[selectedSquare][i] <= MIN) {
value = 0;
colors[selectedSquare][i] = MIN;
}
}
}
glutTimerFunc(FPS, timeWrapper, value);
}
}
}
timeWrapper calls shineEffect if the value passed in the parameter is 1 or -1.
You want the shineEffect function to go through one highlight loop at least, and then stop if the highlighted item has changed. It's more a UI code design issue rather than an OpenGL or GLUT one.
The mechanic you need to implement is pretty straightforward:
install once for all an updateHighlights function with glutTimerFunc: this function will be responsible of updating the highlights of all the clicked elements,
create a queue of elements: each time an element has been clicked, add it to the queue,
The task performed by the updateHighLights function should be as follow:
if the queue contains one element, keep cycling its highlight as you already do in your program
if the queue contain more than one element, for each element in the queue,
step the highlight cycle
if the cycle is over, and the element is not the last one, remove the element from the queue
Here's another perhaps more flexible take on your problem.
The Glut event loop machinery is very simple design: there's only one hook to put your "idle work" code, so it's probably more flexible to install a function there which calls a list of others functions. That list could be then modified with a set primitive, to install or remove specific tasks to perform during idle time. This could be much more flexible than the "one function" approach of GLUT.
For instance, you could isolate your current highlight code in one function with a struct containing the element to highlight, and have the function remove itself from the list when its element is done through a highlight cycle and isn't active anymore.
Since you are using C++, it should be easy to bundle all these functionalities in classes:
one class for the list of idle tasks
one base class for idle tasks
one derived idle task class for the purpose of highlighting a square (with fields for the square and for the active status)
one class to keep track of the active square, so that it may be easily deactivated and replaced by the new active one. This one would be accessed by the glutMouseFunc function.

Killing the invaders doesn't work in C++

I know that in order to kill invaders in C++, I need to make a collider.
However, nothing will ever kill the invaders in that game.
Here's the code in the header:
bool DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight);
This is the function I'm initializing:
bool Game::DoCollision(float Xbpos, float Ybpos, int BulWidth, int BulHeight, float Xipos, float Yipos, int InvWidth, int InvHeight) {
if (Xbpos+BulWidth < Xipos || Xbpos > Xipos+InvWidth) return false;
if (Ybpos+BulHeight < Yipos || Ybpos > Yipos+InvHeight) return false;
return true;
}
And this is what happens if somebody presses the space key:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
}
Does anybody know what's going wrong?
The problem isn't C++. The problem is how you are using it. The only way you'll get a kill with your code as written is if the invader is right on top of you. But that's too late. The alien invader has already killed you.
What you need to do is make those bullets into objects that you propagate over time, just like your invaders are objects that you propagate over time. The response to the user pressing a space key should be to add a new instance of a bullet to the set of active bullets. Each of those active bullets has a position that changes with time. On each time step, you should advance the states of the active invaders per the rules that dictate how invaders move and advance the states of the active bullets per the rules that dictate how bullets move. Remove bullets when they reach the top of the screen, and if an alien invader reaches the bottom of the screen, game over.
After propagating, removing off-screen bullets, and checking for game over, you want to check for collisions between each of the N bullets with each of the M invaders. When a collision is detected, remove the bullet from the set of active bullets and delete the alien invader from the set of active invaders. And of course you'll want some nifty graphics to show the user that another alien bit the dust.
Aside: Being an NxM problem, this check might be the biggest drain on CPU usage. You can speed this up with some simple heuristics.
You could manage the collections of alien invaders and bullets yourself, carefully using new and delete so as to prevent your invaders and bullets from killing your program with a memory leak. You don't have to do this. C++ gives you some nifty tools to manage these collections. Use one of the C++ standard library collections instead of rolling your own collection. For example, std::vector<AlienInvader> invaders; or std::list<AlienInvader> invaders, and the same for bullets. You'll be deleting from the middle a lot, which suggests that std::list or std::deque might be more appropriate than std::vector here.
You test the collision for the fired item just when they are created
Shouldn't be the test collision done in the main loop for each existing item at each frame ?
Don't worry, C++ has got all you need to kill invaders :)))
It's not easy to give advice based on so little code, but here the only logical error seems to be you test for collision only when space is pressed; you should test for it in an outside loop probably:
if (code == 57) { //Space
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
}
From a logical point of view, pressing Space should fire a bullet: the starting position for the bullet is set, and so is its speed on the Y axis (so that it goes up).
The code that check for collision should go outside of this if block. In fact, this block of code is executed only if you're still pressing space -that is: still firing-. Should collision be checked only if you're "still firing"? Do the fact that you fired a bullet and started waiting for it to destroy the invader interfere in some way with the fact that this bullet can reach the invader and, indeed, destroy it? Of course not!
if (DoCollision(Invaders[counter].MyBullet.Xbpos,Invaders[counter].MyBullet.Ybpos,Invaders[counter].MyBullet.BulWidth,
Invaders[counter].MyBullet.BulHeight,Invaders[counter].Xipos,Invaders[counter].Yipos,Invaders[counter].InvWidth,Invaders[counter].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[counter].Active = false;
printf("Collide!\n");
}
You want collision to be checked in an outside loop, the same that probably also contains the checks for key presses. In this way, even if you're just looking at the screen and waiting, the program keeps testing the condition and, when it's fulfilled, code associated with the event of collision is executed (that is: an invader is "inactivated").
You say //Space , is that what it is or should it be 32 (if ASCII) instead of 57? Does the program flow into the if==57 block?
Your code looks fine, but you need two loops around the collision checker: one for checking all invaders (not just one of them) and another one to check at every bullet position along its trajectory, not just the moment when it leaves the gun.
I will assume we have an auxiliary function that moves the bullet and returns whether it is still inside the screen:
bool BulletIsInScreen();
Then we can write the loops:
if (code == 57) { // Space
while (BulletIsInScreen()) {
for (size_t i = 0; i < counter; ++i) { // counter is the number of invaders,
// according to your comment to your own answer
myKeyInvader.MeBullet.Active = true;
myKeyInvader.MeBullet.Xpos = myKeyInvader.Xpos + 10;
myKeyInvader.MeBullet.Ypos = myKeyInvader.Ypos - 10;
myKeyInvader.MeBullet.yvuel = 0.2;
myKeyInvader.MeBullet.BulletP->CopyTo(m_Screen,myKeyInvader.Xpos,myKeyInvader.Ypos);
if (DoCollision(Invaders[i].MyBullet.Xbpos, Invaders[i].MyBullet.Ybpos,
Invaders[i].MyBullet.BulWidth, Invaders[i].MyBullet.BulHeight,
Invaders[i].Xipos, Invaders[i].Yipos,
Invaders[i].InvWidth, Invaders[i].InvHeight)) {
//myKeyInvader.Ypos = 100;
Invaders[i].Active = false;
printf("Collide!\n");
}
}
}
}
Now this should work as expected.

Improving my quadtree design?

I have an application which is used for displaying and modifying huge volumes of point cloud data from lidar files (up to few gigabytes each, sometimes loaded in simultaneously). In the app the user is able to view a 2D image of loaded points (from the top) and select a profile to view in another window (from the side). Again this involves millions of points and they are displayed using OpenGL.
To handle the data there is also a quadtree library, which works, but is extremely slow. It has been used for some time, but recently the lidar point format changed and the LidarPoint object needed a number of attributes (class members) added, which cause it to grow in size in turn affecting the performance to almost unusable level (think 5 minutes to load a single 2GB file).
The quadtree currently consist of pointers to PointBucket objects which are simply arrays of LidarPoint objects with specified capacity and defined boundaries (for spatial queries). If the bucket capacity is exceeded it splits into four buckets. There is also kind of a caching system in place which causes point buckets to get dumped to disk when the point data is taking too much memory. These are then loaded back into memory if needed. Finally every PointBucket contains subbuckets/resolution levels which hold every n-th point of the original data and are used when displaying the data depending on the zoom level. That is because displaying few million points at once, while that level of detail is not necessary, is just extremely slow.
I hope you can get a picture from this. If not please ask and I can provide some more details or upload more code. For example here is the current (and slow) insert method:
// Insert in QuadTree
bool QuadtreeNode::insert(LidarPoint newPoint)
{
// if the point dosen't belong in this subset of the tree return false
if (newPoint.getX() < minX_ || newPoint.getX() > maxX_ ||
newPoint.getY() < minY_ || newPoint.getY() > maxY_)
{
return false;
}
else
{
// if the node has overflowed and is a leaf
if ((numberOfPoints_ + 1) > capacity_ && leaf_ == true)
{
splitNode();
// insert the new point that caused the overflow
if (a_->insert(newPoint))
{
return true;
}
if (b_->insert(newPoint))
{
return true;
}
if (c_->insert(newPoint))
{
return true;
}
if (d_->insert(newPoint))
{
return true;
}
throw OutOfBoundsException("failed to insert new point into any \
of the four child nodes, big problem");
}
// if the node falls within the boundary but this node not a leaf
if (leaf_ == false)
{
return false;
}
// if the node falls within the boundary and will not cause an overflow
else
{
// insert new point
if (bucket_ == NULL)
{
bucket_ = new PointBucket(capacity_, minX_, minY_, maxX_, maxY_,
MCP_, instanceDirectory_, resolutionBase_,
numberOfResolutionLevels_);
}
bucket_->setPoint(newPoint);
numberOfPoints_++;
return true;
}
}
}
// Insert in PointBucket (quadtree holds pointers to PointBuckets which hold the points)
void PointBucket::setPoint(LidarPoint& newPoint)
{
//for each sub bucket
for (int k = 0; k < numberOfResolutionLevels_; ++k)
{
// check if the point falls into this subbucket (always falls into the big one)
if (((numberOfPoints_[0] + 1) % int(pow(resolutionBase_, k)) == 0))
{
if (!incache_[k])
cache(true, k);
// Update max/min intensity/Z values for the bucket.
if (newPoint.getIntensity() > maxIntensity_)
maxIntensity_ = newPoint.getIntensity();
else if (newPoint.getIntensity() < minIntensity_)
minIntensity_ = newPoint.getIntensity();
if (newPoint.getZ() > maxZ_)
maxZ_ = newPoint.getZ();
else if (newPoint.getZ() < minZ_)
minZ_ = newPoint.getZ();
points_[k][numberOfPoints_[k]] = newPoint;
numberOfPoints_[k]++;
}
}
}
Now my question is if you can think of a way to improve this design? What are some general strategies when dealing with huge amounts of data that doesn't fit into memory? How can I make the quadtree more efficient? Is there a way to speed up rendering of points?
Now my question is if you can think of a way to improve this design?
Yes: Don't store the objects itself in the quadtree. Put them into a flat structure (array, linked list, etc.) and have the Quadtree just keep a pointer to the actual objects. If the quadtree has a certain depth (on all nodes), you could flatten it as well.

Better, or advantages in different ways of coding similar functions

I'm writing the code for a GUI (in C++), and right now I'm concerned with the organisation of text in lines. One of the problems I'm having is that the code is getting very long and confusing, and I'm starting to get into a n^2 scenario where for every option I add in for the texts presentation, the number of functions I have to write is the square of that. In trying to deal with this, A particular design choice has come up, and I don't know the better method, or the extent of the advantages or disadvantages between them:
I have two methods which are very similar in flow, i.e, iterate through the same objects, taking into account the same constraints, but ultimately perform different operations between this flow. For anyones interest, the methods render the text, and determine if any text overflows the line due to wrapping the text around other objects or simply the end of the line respectively.
These functions need to be copied and rewritten for left, right or centred text, which have different flow, so whatever design choice I make would be repeated three times.
Basically, I could continue what I have now, which is two separate methods to handle these different actions, or I could merge them into one function, which has if statements within it to determine whether or not to render the text or figure out if any text overflows.
Is there a generally accepted right way to going about this? Otherwise, what are the tradeoffs concerned, what are the signs that might indicate one way should be used over the other? Is there some other way of doing things I've missed?
I've edited through this a few times to try and make it more understandable, but if it isn't please ask me some questions so I can edit and explain. I can also post the source code of the two different methods, but they use a lot of functions and objects that would take too long to explain.
// EDIT: Source Code //
Function 1:
void GUITextLine::renderLeftShifted(const GUIRenderInfo& renderInfo) {
if(m_renderLines.empty())
return;
Uint iL = 0;
Array2t<float> renderCoords;
renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[0].s_x;
renderCoords.s_y = renderInfo.s_offset.s_y + m_y;
float remainingPixelsInLine = m_renderLines[0].s_y;
for (Uint iTO= 0;iTO != m_text.size();++iTO)
{
if(m_text[iTO].s_pixelWidth <= remainingPixelsInLine)
{
string preview = m_text[iTO].s_string;
m_text[iTO].render(&renderCoords);
remainingPixelsInLine -= m_text[iTO].s_pixelWidth;
}
else
{
FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();
float characterWidth = 0;
Uint iFirstCharacterOfRenderLine = 0;
for(Uint iC = 0;;++iC)
{
if(iC == m_text[iTO].s_string.size())
{
// wrap up
string renderPart = m_text[iTO].s_string;
renderPart.erase(iC, renderPart.size());
renderPart.erase(0, iFirstCharacterOfRenderLine);
m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
&renderCoords);
break;
}
characterWidth += m_text[iTO].s_font->getWidthOfGlyph(intData,
m_text[iTO].s_string[iC]);
if(characterWidth > remainingPixelsInLine)
{
// Can't push in the last character
// No more space in this line
// First though, render what we already have:
string renderPart = m_text[iTO].s_string;
renderPart.erase(iC, renderPart.size());
renderPart.erase(0, iFirstCharacterOfRenderLine);
m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
&renderCoords);
if(++iL != m_renderLines.size())
{
remainingPixelsInLine = m_renderLines[iL].s_y;
renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[iL].s_x;
// Cool, so now try rendering this character again
--iC;
iFirstCharacterOfRenderLine = iC;
characterWidth = 0;
}
else
{
// Quit
break;
}
}
}
}
}
// Done! }
Function 2:
vector GUITextLine::recalculateWrappingContraints_LeftShift()
{
m_pixelsOfCharacters = 0;
float pixelsRemaining = m_renderLines[0].s_y;
Uint iRL = 0;
// Go through every text object, fiting them into render lines
for(Uint iTO = 0;iTO != m_text.size();++iTO)
{
// If an entire text object fits in a single line
if(pixelsRemaining >= m_text[iTO].s_pixelWidth)
{
pixelsRemaining -= m_text[iTO].s_pixelWidth;
m_pixelsOfCharacters += m_text[iTO].s_pixelWidth;
}
// Otherwise, character by character
else
{
// Get some data now we don't get it every function call
FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();
for(Uint iC = 0; iC != m_text[iTO].s_string.size();++iC)
{
float characterWidth = m_text[iTO].s_font->getWidthOfGlyph(intData, '-');
if(characterWidth < pixelsRemaining)
{
pixelsRemaining -= characterWidth;
m_pixelsOfCharacters += characterWidth;
}
else // End of render line!
{
m_pixelsOfWrapperCharacters += pixelsRemaining; // we might track how much wrapping px we use
// If this is true, then we ran out of render lines before we ran out of text. Means we have some overflow to return
if(++iRL == m_renderLines.size())
{
return harvestOverflowFrom(iTO, iC);
}
else
{
pixelsRemaining = m_renderLines[iRL].s_y;
}
}
}
}
}
vector<GUIText> emptyOverflow;
return emptyOverflow; }
So basically, render() takes renderCoordinates as a parameter and gets from it the global position of where it needs to render from. calcWrappingConstraints figures out how much text in the object goes over the allocated space, and returns that text as a function.
m_renderLines is an std::vector of a two float structure, where .s_x = where rendering can start and .s_y = how large the space for rendering is - not, its essentially width of the 'renderLine', not where it ends.
m_text is an std::vector of GUIText objects, which contain a string of text, and some data, like style, colour, size ect. It also contains under s_font, a reference to a font object, which performs rendering, calculating the width of a glyph, ect.
Hopefully this clears things up.
There is no generally accepted way in this case.
However, common practice in any programming scenario is to remove duplicated code.
I think you're getting stuck on how to divide code by direction, when direction changes the outcome too much to make this division. In these cases, focus on the common portions of the three algorithms and divide them into tasks.
I did something similar when I duplicated WinForms flow layout control for MFC. I dealt with two types of objects: fixed positional (your pictures etc.) and auto positional (your words).
In the example you provided I can list out common portions of your example.
Write Line (direction)
bool TestPlaceWord (direction) // returns false if it cannot place word next to previous word
bool WrapPastObject (direction) // returns false if it runs out of line
bool WrapLine (direction) // returns false if it runs out of space for new line.
Each of these would be performed no matter what direction you are faced with.
Ultimately, the algorithm for each direction is just too different to simplify anymore than that.
How about an implementation of the Visitor Pattern? It sounds like it might be the kind of thing you are after.