turtle graphics: starting a new line - c++

Sorry for the massive block of code ;w;
I'm learning C++, and this is an assignment I'm stuck on- I'm supposed to be making a brick wall with alternating rows offset by 1/2 bricks, and I'm supposed to be using a nested loop to do so.
I've got the functions to draw the full brick and half bricks, and I've successfully been able to create a full line of 9 bricks(9 being how many bricks can span the window) and I'm stuck on the next step. I need to make the program draw the next line after the first one is finished, but "\n" and "cout << endl;" only affect the main window and not the "TurtleWindow" that OpenCV opens. All I have in that regard is that it has something to do with the "changePosition" command, but I'm not sure how to add that in to my loop. If I set position to some specific (x, y) coords, then wouldn't it just keep setting the "bricks" in that position every loop?
Any help would be appreciated, I feel like I'm so close to the solution but this is stumping me...
// BrickWall.cpp : This file contains the 'main' function. Program execution begins
//and ends there.
//
#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
#include <math.h>
using namespace cv;
using namespace std;
#define M_PI 3.14159265358979323846264338327950288
#define degToRad(angleInDegrees) ((angleInDegrees) * M_PI / 180.0)
char wndname[] = "TurtleWindow";
Mat image = Mat::zeros(500, 500, CV_8UC3);
Scalar WHITE(255, 255, 255);
const int DELAY = 1;
Point _curPosition(250, 250);
int _direction = 0;
void init()
{
imshow(wndname, image);
waitKey(DELAY);
}
//
// Move the pen to the given coordinates without leaving a mark
//
// Note (0,0) refers to the upper left corner
// (500,500) refers to the bottom right corner
//
void changePosition(int x, int y)
{
_curPosition.x = x;
_curPosition.y = y;
}
//
// point in the direction given in degrees
// 0 ==> point right
// 90 ==> point down
// 180 ==> point left
// 270 ==> point up
//
void changeDirection(int direction)
{
_direction = direction;
}
//
// Moves the pen forward the given number of pixels
// Note leaves a mark creating a line from the previous point
// to the new point
//
void moveForward(int nPixels)
{
int x = static_cast<int>(round(nPixels * cos(degToRad(_direction))));
int y = static_cast<int>(round(nPixels * sin(degToRad(_direction))));
Point newPoint = Point(x + _curPosition.x, y + _curPosition.y);
line(image, _curPosition, newPoint, WHITE);
_curPosition = newPoint;
// cout << "moved to " << newPoint.x << "," << newPoint.y << endl;
imshow(wndname, image);
waitKey(DELAY);
}
void fullBrick()
// changePosition(25, 25);
{
changeDirection(0);
moveForward(50);
changeDirection(90);
moveForward(20);
changeDirection(180);
moveForward(50);
changeDirection(270);
moveForward(20);
changeDirection(0);
moveForward(50);
}
void halfBrick()
//changePosition(25, 45);
{
changeDirection(0);
moveForward(25);
changeDirection(90);
moveForward(20);
changeDirection(180);
moveForward(25);
changeDirection(270);
moveForward(20);
}
int main()
{
int counter;
int counterWall;
counterWall = 0;
counter = 0;
init();
changePosition(25, 25);
while (counter < 20)
{
do
{
changeDirection(0);
moveForward(50);
changeDirection(90);
moveForward(20);
changeDirection(180);
moveForward(50);
changeDirection(270);
moveForward(20);
changeDirection(0);
moveForward(50);
counterWall++;
} while (counterWall < 9);
counter++;
}
waitKey();
}
edit: thanks everyone for the advice! I was fully intending to use a nested loop in the end(and did use one, so no lost points there!) and was able to realize there was nothing stopping me from looping the bricks like a snake. I had to turn the assignment in before I could try any of the changes you guys offered, but I'll be sure to keep them in mind for future assignments!
and here's a link to the picture of the final product, I've never been happier to see a brick wall in my life
Brick Wall Picture

Related

How do I get a destructor on an object in a vector not to throw a failed assertion? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I'm programming a Breakout game in C++. I'm having a HUGE problem that's preventing me from giving the game multi-ball functionality. I think it has something to do with the destructor. Have a look:
for loop for the balls (Driver.cpp):
for (Ball& b : balls) { // Loops over all balls
(...)
// Collision for when you miss
if (b.getYPos() > HEIGHT) { // If the ball falls below the defined height of the screen
balls.erase(balls.begin() + b.getID()); // Wipe the ball out of memory to make room (Troublesome line)
Ball::addToID(-1); // Shift the ball ID to assign to the next ball back one
(...)
}
And I get this error:
Debug Error!
Program: Breakout.exe
abort() has been called
(Press Retry to debug the application)
Do you know why this mysterious crash is happening? Or more importantly, a fix for it?
Here's a replicable piece of code to help:
Driver.cpp:
#include <vector>
#include <allegro5\allegro.h>
#include "Ball.h"
using namespace std;
vector<Ball> balls(0); // Pay attention to this line
const POS WIDTH = 1600, HEIGHT = 900;
int main {
while (running) {
if (al_key_down(&key, ALLEGRO_KEY_SPACE)) { // Spawn the ball
balls.push_back(Ball(WIDTH / 2, 500, 10, 10)); // Spawn the ball
balls[Ball::getIDtoAssign()].setYSpeed(5);
}
for (Ball& b : balls) { // Pay attention to this loop
b.draw(); // This line is what's crashing.
b.move();
(...)
// Collision for when you miss
balls.erase(
remove_if(balls.begin(), balls.end(),
[=](Ball& b) {
// Collision for when you miss
return b.getYPos() > HEIGHT; // If the ball falls below the defined height of the screen, wipe the ball out of memory to make room
}
),
balls.end()
);
}
}
}
}
return 0;
}
Ball.h:
#pragma once
#include <allegro5\allegro_primitives.h>
using namespace std;
class Ball {
public:
Ball();
Ball(float x, float y, float w, float h);
~Ball();
void draw();
void move();
float getYPos();
void setYSpeed(float set);
private:
float xPos; // Horizontal position
float yPos; // Vertical position (upside down)
float width; // Sprite width
float height; // Sprite height
float xSpeed; // Horizontal speed
float ySpeed; // Vertical speed (inverted)
}
Ball.cpp:
#include "Ball.h"
short Ball::ballIDtoAssign = 0;
Ball::Ball() {
this->xPos = 0;
this->yPos = 0;
this->width = 0;
this->height = 0;
this->xSpeed = 0;
this->ySpeed = 0;
}
Ball::Ball(float x, float y, float w, float h) {
this->xPos = x;
this->yPos = y;
this->width = w;
this->height = h;
this->xSpeed = 0;
this->ySpeed = 0;
}
Ball::~Ball() {
// Destructor
}
void Ball::draw() {
al_draw_filled_rectangle(xPos, yPos, xPos + width, yPos + height, al_map_rgb(0xFF, 0xFF, 0xFF));
}
void Ball::move() {
xPos += xSpeed;
yPos += ySpeed;
}
float Ball::getYPos() {
return yPos;
}
void Ball::setYSpeed(float set) {
ySpeed = set;
}
You cannot modify a container while you are iterating through it with a range-for loop. You don't have access to the iterator that the loop uses internally, and erase() will invalidate that iterator.
You can use the container's iterators manually, paying attention to the new iterator that erase() returns, eg:
for(auto iter = balls.begin(); iter != balls.end(); ) { // Loops over all balls
Ball& b = *iter:
...
// Collision for when you miss
if (b.getYPos() > HEIGHT) { // If the ball falls below the defined height of the screen
...
iter = balls.erase(iter); // Wipe the ball out of memory to make room
}
else {
++iter;
}
}
Alternatively, use the erase-remove idiom via std::remove_if() instead:
balls.erase(
std::remove_if(balls.begin(), balls.end(),
[=](Ball &b){
// Collision for when you miss
return b.getYPos() > HEIGHT; // If the ball falls below the defined height of the screen, wipe the ball out of memory to make room
}
),
balls.end()
);
UPDATE: now that you have posted more of your code, it is clear to see that you are trying to use ID numbers as indexes into the vector, but you are not implementing those IDs correctly, and they are completely unnecessary and should be eliminated.
The Ball::ballID member is never being assigned any value, so in this statement:
balls.erase(balls.begin() + b.getID()); // The troublesome line
Trying to erase() the result of balls.begin() + b.getID() causes undefined behavior since the iterator has an indeterminate value, thus you can end up trying to erase the wrong Ball object, or even an invalid Ball object (which is likely the root cause of your runtime crash).
Also, in this section of code:
balls.push_back(Ball(WIDTH / 2, 500, 10, 10)); // Spawn the ball
balls[Ball::getIDtoAssign()].setYSpeed(5);
Ball::addToID(1);
Since you want to access the Ball object you just pushed, that code can be simplified to this:
balls.back().setYSpeed(5);
And I already gave you code further above to show you how to remove balls from the vector without using IDs.
So, there is need for an ID system at all.
With that said, try something more like this:
Driver.cpp:
#include <vector>
...
#include "Ball.h"
using namespace std;
vector<Ball> balls;
const POS WIDTH = 1600, HEIGHT = 900;
int main {
...
while (running) {
...
if (input.type == ALLEGRO_EVENT_TIMER) { // Runs at 60FPS
...
if (al_key_down(&key, ALLEGRO_KEY_SPACE)) { // Spawn the ball
balls.push_back(Ball(WIDTH / 2, 500, 10, 10)); // Spawn the ball
balls.back().setYSpeed(5);
}
for (auto iter = balls.begin(); iter != balls.end(); ) {
Ball &b = *iter;
...
if (b.getYPos() > HEIGHT) { // Collision for when you miss
iter = balls.erase(iter);
}
else {
++iter;
}
}
/* alternatively:
for (Ball& b : balls) {
b.draw();
b.move();
}
balls.erase(
std::remove_if(balls.begin(), balls.end(),
[=](Ball &b){
// Collision for when you miss
return b.getYPos() > HEIGHT; // If the ball falls below the defined height of the screen, wipe the ball out of memory to make room
}
),
balls.end()
);
*/
}
}
return 0;
}
Ball.h:
#pragma once
...
class Ball {
public:
...
// NO ID METHODS!
private:
...
// NO ID MEMBERS!
}
Ball.cpp:
#include "Ball.h"
...
// NO ID MEMBER/METHODS!
OK, so I managed to figure out why the program crashes. It was because I had the erase-remove inside the for loop which can cause all sorts of problems.

C++ / SFML: Printing convex shapes to the screen using two recursive calls only displays the shapes from the first recursive call and not the second

I am using SFML and coding in C++. The program I am writing must be a recursive implementation.
My goal is to create a function that recursively draws a square to the screen in different positions and rotations dependent upon the previously drawn square.
Each subsequent square should be smaller than the previous function call and rotated 45 degrees to the left( from the left corner of the previous square ) or 45 to the right of the previous square.
Each new square spawns two more squares etc..
My idea is to pass the upper left point and the upper right point of a square to two different recursive function calls and use these points as starting points for the subsequent squares.
While the squares generated will also pass upper left and right corners to recursive function calls etc..
The code I have developed is not displaying both squares that should have been generated from the recursive function calls. Only one side is being shown.
I have developed the following code (Please forgive my code.. I haven't been coding in C++ for too long..)
DRIVER of PROGRAM ( main.cpp )
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include "PTree.hpp"
using namespace std;
using namespace sf;
int main( int argc, char* argv[ ] )
{
double L = 0.0; // Length of square sides
int N = 0; // Number of times to call recursive function
L = atol( argv[ 1 ] );
N = atoi( argv[ 2 ] );
Vector2f vPoint;
vPoint.x = 0;
vPoint.y = 0;
// Create and Display Window
PTree tree( L, N );
return 0;
}
( PTree.hpp )
#ifndef PTREE_H
#define PTREE_H
using namespace std;
using namespace sf;
class PTree /*:public sf::Drawable, public sf::Transformable*/{
public:
// Constructor
PTree( double L, int N );
// Destructor
~PTree();
// Recursive function to draw Pythagorias Tree
void pTree( double L, int N, Vector2f vPoint, Vector2f vOrigin, float rotation );
private:
float width = 0;
float height = 0;
int originX = 0;
int originY = 0;
float rotation = 0;
RenderWindow window;
int angle1 = 0;
int angle2 = 0;
};
#endif // PTREE_H included
( PTree.cpp )
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <math.h>
#include "PTree.hpp"
#include <iostream>
using namespace std;
using namespace sf;
// Constructor
PTree::PTree( double L, int N )
{
width = ( 6 * L );
height = ( 4 * L );
Vector2f vPoint = { width/2, height - 1 };
Vector2f vOrigin;
vOrigin.x = L/2;
vOrigin.y = L;
/* vPoint.x = width/2;
vPoint.y = height - 1;
*/
window.create( VideoMode( width, height ), "Pythagoras Fractal Tree" );
pTree( L, N, vPoint, vOrigin, 0 );
}
// Destructor
PTree::~PTree(){}
/*###########################################################################*/
// Recursive function to draw Pythagorias Tree
void PTree::pTree( double L, int N, Vector2f vPoint, Vector2f vOrigin, float rotation )
{
Vector2f vPointR;
if( N < 1 )
{
return;
}
// Define a convex shape called convexSquare
ConvexShape convexSquare( 4 );
convexSquare.setPoint( 0, Vector2f( 0, 0 ));
convexSquare.setPoint( 1, Vector2f( 0, L ));
convexSquare.setPoint( 2, Vector2f( L, L ));
convexSquare.setPoint( 3, Vector2f( L, 0 ));
convexSquare.setOutlineThickness( 1.f );
convexSquare.setFillColor( Color::Black );
convexSquare.setOutlineColor( Color::White );
convexSquare.setPosition( vPoint );
convexSquare.setOrigin( vOrigin );
convexSquare.setRotation( rotation );
while( window.isOpen( ))
{
Event event;
while( window.pollEvent( event ))
{
if( event.type == Event::Closed )
{
window.close( );
}
}
if( N >= 0 )
{
window.draw( convexSquare );
window.display( );
L = ( L * ( sqrt(2)/2 ));
N = N - 1;
rotation = rotation - 135;
cout << "LOOPS:" << N << endl;
//left
vPoint = convexSquare.getTransform( ).transformPoint( convexSquare.getPoint( 0 ));
vOrigin = convexSquare.getPoint( (angle1) );
pTree( L, N, vPoint, vOrigin, rotation );
angle1 = (( angle1 + 1 ) % 4 );
//right
vPointR = convexSquare.getTransform( ).transformPoint( convexSquare.getPoint( 3 ));
vOrigin = convexSquare.getPoint( 2 );
pTree( L, N, vPointR, vOrigin, rotation-90 );
}
}
cout << "X value =" << vPoint.x << " Y value = " << vPoint.y << endl;
So far I have tried to return various points of the convex shapes for the second recursive call to the function pTree. This did not display anything either.
Initially I was only using Vector2f vPoint and modifying it prior to each recursive call but after exhausting my knowledge base for a solution I created a new variable specifically for the right side squares called Vector2f vPointR.
The SFML documentation does not provide sufficient examples for noobs like myself. The API is essentially a list of options with minimal examples if any for each function. Ive searched the internet to the best of my ability to see if I am passing the wrong points but could not find an answer.
The one thing that did work ( although not entirely correct ) was when I switched the recursive calls... meaning I moved the call for the right side squares before the call for the left side squares but the problem with this is that the left side s
quares were not displaying.
At this point I am also trying to work out the proper rotation for each square but this is the least of my problems.
Is there an issue with the way I am trying to display these squares recursively?
I am not sure where to go from here other than Stack Overflow for help.
Thanks for your time and expertise.
Don't recursively call the entire while loop. Only recurively call the drawing part
// Initialize window...
while (window.isOpen())
{
sf::Event event;
// Handle events...
window.clear();
// call the recursive function here
window.display();
}
Also you may want to use sf::RectangleShape to draw instead of sf::ConvexShape
Here's a working "example":
#include <SFML/Graphics.hpp>
#include <cmath>
void drawPythagoreanTree(sf::RenderTarget&, const float, const int);
int main()
{
const float L = 150;
const int N = 14;
const unsigned width = static_cast<unsigned>(6 * L);
const unsigned height = static_cast<unsigned>(4 * L);
sf::RenderWindow window{{width, height}, "Pythagorean Tree"};
while (window.isOpen())
{
for (sf::Event event; window.pollEvent(event);)
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color::White);
drawPythagoreanTree(window, L, N);
window.display();
}
}
void drawPythagoreanTree(sf::RenderTarget& target, const int N,
const sf::RectangleShape& parent)
{
static const float halfSqrt2 = sqrt(2.f) / 2;
if (N < 1) return;
target.draw(parent);
auto const& sz = parent.getSize();
auto const& tf = parent.getTransform();
auto childL = parent; // copy parent's color and rotation
childL.setSize(sz * halfSqrt2); // resize
childL.setOrigin(0, childL.getSize().y); // bottom left corner
childL.setPosition(tf.transformPoint({0, 0})); // reposition
childL.rotate(-45);
drawPythagoreanTree(target, N - 1, childL);
auto childR = parent; // copy parent's color and rotation
childR.setSize(sz * halfSqrt2); // resize
childR.setOrigin(childR.getSize()); // bottom right corner
childR.setPosition(tf.transformPoint({sz.x, 0})); // reposition
childR.rotate(45);
drawPythagoreanTree(target, N - 1, childR);
}
void drawPythagoreanTree(sf::RenderTarget& target, const float L, const int N)
{
sf::RectangleShape rect{{L, L}};
// set origin to center of the rect, easier to center position on screen
rect.setOrigin(rect.getSize() / 2.f);
rect.setPosition(target.getSize().x / 2.f, target.getSize().y - L / 2.f);
rect.setFillColor(sf::Color::Black);
drawPythagoreanTree(target, N, rect);
}

Adding multiple shapes using the FLK library

I have been trying to make a checkered image.
I can print out everything just fine but I want to find a way to duplicate the shapes of different colors so that I won't have to wast time creating 64 rectangles. I really don't know where to go from here.
#include "Window.h"
#include "Graph.h"
#include "std_lib_facilities_5.h"
#include "Simple_window.h"
#include "FL/Fl_JPEG_Image.H"
int main()
try {
Here is the window being create using the Simple_window struct.
Point tl{ 100,100 };
Simple_window win{ tl,440,440,"Canvas" };
Find the maximum distances than can be given on a window and set the values up as integers (both going in x and y dimensions). x_grid and y_grid are dimensions of a single grid square.
int x_size = win.x_max();
int y_size = win.y_max();
int x_grid = 55;
int y_grid = 55;
Use a Lines class to build the grid. For loops are made to determine where the lines will be placed to form a grid.
Lines grid;
for (int x = x_grid; x < x_size; x += x_grid) {
grid.add(Point{ x,0 }, Point{ x,y_size });
}
for (int y = y_grid; y < y_size; y += y_grid) {
grid.add(Point{ 0,y }, Point{ x_size,y });
}
win.attach(grid);
So here I created two different colors but of the same size using the rectangle class.
So right now I have placed the squared at only one point. However like I said before, I need them to be all over the image. Is there any other way besides making 64 shapes where I can have them copies of the squares? I assume there are some loops involved.
Rectangle rx1(Point(55, 0), 55, 55);
Color moss_green(fl_rgb_color(173, 223, 173));
rx1.set_color(Color::invisible);
rx1.set_fill_color(moss_green);
win.attach(rx1);
Rectangle ry1(Point(0, 0), 55, 55);
Color cherry_blossom_pink(fl_rgb_color(255, 183, 197));
ry1.set_color(Color::invisible);
ry1.set_fill_color(cherry_blossom_pink);
win.attach(ry1);
win.wait_for_button();
}
catch (exception& e) {
cerr << "exception: " << e.what() << endl;
keep_window_open();
}
catch (...) {
cerr << "exception\n";
keep_window_open();
}

Need help optimizing C++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have programmed a simple top-down car driving game that resembles the first GTA, on the GameBoyAdvance. I have used only vector graphics for doing so, and the GBA doesn't handle it very well; basically with 5 pedestrian instances it lags.
I don't have much experience in optimizing code, so I would like to know if there are some tweaks I could make to my code in order to make it run faster, not depending on the fact that it runs on a GBA.
The collision testing I use is SAT (separating axis theorem) as I've found it to be the easisest one for collision check with vector graphics; the game is very simple itself.
Here is the code:
/*
GTA Vector City
Author: Alberto Taiuti
Version: 2.0
*/
#include "Global.h"
#include <string.h>
#include <cstdio>
#include "font.h"
#include "CVector2D.h"
#include "CCar.h"
#include "CPed.h"
#include <vector>
#include <memory>
/* GLOBAL VARIABLES */
void CheckCollisionsRect(CRect *test_a, CRect *test_b);
std::vector<CVector2D> PrepVectors(CRect *shape);
CVector2D GetMinMaxShape(std::vector<CVector2D> vect_shape, CVector2D axis);
void CheckCollisionRectVSPoint(CRect *test_a, CVector2D *point);
/* MAIN */
// The entry point for the game
int main()
{
// Frame counter
uint32_t frames = 0;
// Previous & current buttons states
static uint16_t prev_buttons = 0, cur_buttons = 0;
// Put the display into bitmap mode 3, and enable background 2.
REG_DISPCNT = MODE4 | BG2_ENABLE;
// Set up the palette.
SetPaletteBG(BLACK, RGB(0, 0, 0)); // black
SetPaletteBG(WHITE, RGB(31, 31, 31)); // white
SetPaletteBG(GREY, RGB(15, 15, 15)); // grey
SetPaletteBG(RED, RGB(31, 0, 0)); // red
SetPaletteBG(GREEN, RGB(0, 31, 0)); // green
SetPaletteBG(BLUE, RGB(0, 0, 31)); // blue
// Create car instance
CCar *car = new CCar(50,50);
// Create a building
/*CRect *test_b = new CRect(100.0f, 100.0f, 30, 30);
CRect *test_c = new CRect(120.0f, 120.0f, 30, 30);
CRect *test_d = new CRect(30.0f, 30.0f, 30, 30);*/
// Pedestrian instances
int ped_number = 10; // Number of pedestrians
std::vector<CPed*> peds; // Ped. entities container (made of smart pointers)
typedef std::vector<CPed*>::iterator p_itor; // Iterator
for(int i = 1; i <= ped_number; i++)
{
peds.push_back(new CPed(i, RED, 2.0f));
}
// Check whether the game is over
bool end = false;
// Main loop
while (!end)
{
// Flip the screen
FlipBuffers();
//Clear the screen
ClearScreen8(BLACK);
// Update frame counter
frames ++;
// Get the current state of the buttons.
cur_buttons = REG_KEYINPUT;
// Handle Input
car->HandleInput(prev_buttons, cur_buttons);
// Logic
car->Update();
for(int i = 0; i < ped_number; i++)
{
peds[i]->Update();
}
for(int i = 0; i < ped_number; i++)
{
CheckCollisionRectVSPoint(car->shape, peds[i]->pos);
}
/*CheckCollisionsRect(car->shape, test_b);
CheckCollisionsRect(car->shape, test_c);
CheckCollisionsRect(car->shape, test_d);
CheckCollisionRectVSPoint(car->shape, test_ped->pos);*/
// Render
car->Draw();
for(int i = 0; i < ped_number; i++)
{
peds[i]->Draw();
}
/*test_b->DrawFrame8(GREEN);
test_c->DrawFrame8(WHITE);
test_d->DrawFrame8(RED);
test_ped->Draw();*/
prev_buttons = cur_buttons;
// VSync
WaitVSync();
}
// Free memory
delete car;
//delete test_b; delete test_c; delete test_d;
//delete test_ped;
for(p_itor itor = peds.begin(); itor != peds.end(); itor ++)// Delete pedestrians
{
peds.erase(itor);
}
return 0;
}
void CheckCollisionsRect(CRect *test_a, CRect *test_b)
{
// If the two shapes are close enough, check for collision, otherways skip and save calculations to the CPU
//if((pow((test_a->points[0]->x - test_b->points[0]->x), 2) + pow((test_a->points[0]->y - test_b->points[0]->y), 2)) < 25.0f)
{
// Prepare the normals for both shapes
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();
std::vector<CVector2D> normals_b = test_b->GetNormalsAsArray();
// Create two containers for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);
std::vector<CVector2D> vect_test_b = PrepVectors(test_b);
// Get the min and max vectors for each shape for each projection (needed for SAT)
CVector2D result_P1 = GetMinMaxShape(vect_test_a, normals_a[1]); //
CVector2D result_P2 = GetMinMaxShape(vect_test_b, normals_a[1]); //
// If the two objects are not colliding
if(result_P1.y < result_P2.x || result_P2.y < result_P1.x)
{
return;
}
CVector2D result_Q1 = GetMinMaxShape(vect_test_a, normals_a[0]); // First axis couple
CVector2D result_Q2 = GetMinMaxShape(vect_test_b, normals_a[0]); //
if(result_Q1.y < result_Q2.x || result_Q2.y < result_Q1.x)
{
return;
}
CVector2D result_R1 = GetMinMaxShape(vect_test_a, normals_b[1]); //
CVector2D result_R2 = GetMinMaxShape(vect_test_b, normals_b[1]); //
if(result_R1.y < result_R2.x || result_R2.y < result_R1.x)
{
return;
}
CVector2D result_S1 = GetMinMaxShape(vect_test_a, normals_b[0]); // Second axis couple
CVector2D result_S2 = GetMinMaxShape(vect_test_b, normals_b[0]); //
if(result_S1.y < result_S2.x || result_S2.y < result_S1.x)
{
return;
}
// Do something
PlotPixel8(200, 10, WHITE);
PlotPixel8(200, 11, WHITE);
PlotPixel8(200, 12, WHITE);
}
}
// Check for collision between an OOBB and a point
void CheckCollisionRectVSPoint(CRect *test_a, CVector2D *point)
{
// Prepare the normals for the shape
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();
// Create a container for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);
// Get projections for the OOBB (needed for SAT)
CVector2D result_P1 = GetMinMaxShape(vect_test_a, normals_a[1]);
float result_point = point->DotProduct(normals_a[1]);
// If the two objects are not colliding on this axis
if(result_P1.y < result_point || result_point < result_P1.x)
{
return;
}
CVector2D result_Q1 = GetMinMaxShape(vect_test_a, normals_a[0]);
result_point = point->DotProduct(normals_a[0]);
// If the two objects are not colliding on this axis
if(result_Q1.y < result_point || result_point < result_Q1.x)
{
return;
}
// Do something
PlotPixel8(200, 10, WHITE);
PlotPixel8(200, 11, WHITE);
PlotPixel8(200, 12, WHITE);
}
// Returns a container with projection vectors for a given shape
std::vector<CVector2D> PrepVectors(CRect *shape)
{
std::vector<CVector2D> vect;
// Create vectors for projection and load them into the arrays
for( uint16_t i=0; i < 5; i++)
{
// Get global position of vectors and then add them to the array
vect.push_back(shape->GetVectorGlobal(i));
}
return vect;
}
CVector2D GetMinMaxShape(std::vector<CVector2D> vect_shape, CVector2D axis)
{
// Set initial minimum and maximum for shape's projection vectors
float min_proj = vect_shape[1].DotProduct(axis);
float max_proj = vect_shape[1].DotProduct(axis);
// Calculate max and min projection vectors by iterating along all of the corners
for(uint16_t i = 2; i < vect_shape.size(); i ++)
{
float current_proj = vect_shape[i].DotProduct(axis);
// Select minimum projection on axis
if(current_proj < min_proj) // If current projection is smaller than the minimum one
min_proj = current_proj;
// Select maximum projection on axis
if(current_proj > max_proj) // If current projection is greater than the minimum one
max_proj = current_proj;
}
return (CVector2D(min_proj, max_proj)); // Return a vector2D as it is a handy way for returning a couple of values
}
Many thanks in advance to everyone and sorry for the messy code!
I gave it a really quick reading so I may have overlooked something. Well, there are obvious tips for improving performance such as passing vectors to functions by reference. Using prefix incrementation instead of postfix is also a good habit. These two rules are definitely nothing like 'premature optimization the, root of ...'. Do not delete pedestrians one by one but use std::vector::clear(). And If you claim you use smart pointers, you shoud, because it seems you have memory leak because you did not delete the pedestrian pointers. And use const keyword whereever possible. Once you make the obvious correction, and the speed is still not satisfactory, then you need to use profiler.
And read something about optimization, here for example: http://www.agner.org/optimize/optimizing_cpp.pdf
One thing leaps out at me (apart from the continuous passing of vectors by value rather than reference, which will be incredibly costly!)
In you collision detection, you're seeing if the car hits each pedestrian
for(int i = 0; i < ped_number; i++)
{
CheckCollisionRectVSPoint(car->shape, peds[i]->pos);
}
Then, in the collision detector, you're repeating a lot of the same processing on the car shape every time:-
// Prepare the normals for both shapes
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();
// Create two containers for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);
.. etc...
You should rework that loop to create the normals etc for the car just once, and then reuse the results for each check against a pedestrian.

Writing text to a postscript file using several class objects

(Full question is listed at the bottom)
I have an assignment that requires me to write text to a postscript file that allows me to draw "Gosper" curves using recursion. However, the test driver (GosperDriver.cpp) my professor has given us resembles the following:
#include "Gosper.h"
#include <iostream>
using namespace std;
int main( )
{
// test right hexagonal Gosper curve at level 4
Gosper gosper1( 100, 100, 0 );
gosper1.rightCurve( 4, 4 );
// test left hexagonal Gosper curver at level 4
Gosper gosper2( 500, 100, 0 );
gosper2.leftCurve( 4, 4 );
// test right hexagonal Gosper curve at level 3
Gosper gosper3( 100, 400, 0 );
gosper3.rightCurve( 3, 6 );
// test left hexagonal Gosper curver at level 3
Gosper gosper4( 500, 400, 0 );
gosper4.leftCurve( 3, 6 );
// test right hexagonal Gosper curve at level 2
Gosper gosper5( 100, 600, 0 );
gosper5.rightCurve( 2, 8 );
// test left hexagonal Gosper curver at level 2
Gosper gosper6( 500, 600, 0 );
gosper6.leftCurve( 2, 8 );
// test right hexagonal Gosper curve at level 1
Gosper gosper7( 100, 700, 0 );
gosper7.rightCurve( 1, 10 );
// test left hexagonal Gosper curver at level 1
Gosper gosper8( 500, 700, 0 );
gosper8.leftCurve( 1, 10 );
}
Gosper.h includes Turtle.h, which contains the "draw" functions which are vital to the project.
Here are my Gosper.h, Gosper.cpp, Turtle.h, and Turtle.cpp files, in that order (I'll cut out the unnecessary code, which controls drawing):
Gosper.h:
// Sierpinski Class
#ifndef GOSPER_H
#define GOSPER_H
#include "Turtle.h"
#include <iostream>
#include <fstream>
using namespace std;
class Gosper : Turtle
{
public:
Gosper(float initX=0.0, float initY=0.0, float initA=0.0);
void leftCurve( int l, float d ); // Draw level l left curve with dist d
void rightCurve( int l, float d ); // Draw level l right curve with dist d
};
#endif
Gosper.cpp:
#include <iostream>
#include <string>
#include "Gosper.h"
// Initialization and such.
Gosper::Gosper(float initX, float initY, float initA)
{
}
void Gosper::leftCurve(int level, float d)
{
// Code that uses draw() function of Turtle.h and Turtle.cpp
}
void Gosper::rightCurve(int level, float d)
{
// Same as above
}
Turtle.h:
#ifndef TURTLE_H
#define TURTLE_H
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;
const float PI = 3.1459265;
class Turtle {
public:
Turtle(float initX = 0.0, float initY = 0.0, float initA = 0.0);
~Turtle();
void draw( float d ); // draw line by distance d
void move( float d ); // simply move by distance d
void turn( float a ); // turn by angle a
private:
ofstream out;
float angle; // current angle
};
Turtle.cpp:
#include "Turtle.h"
#include <iostream>
#include <fstream>
Turtle::Turtle(float initX, float initY, float initA)
{
out.open("output.ps");
out << "%!PS-Adobe-2.0" << endl;
out << initX << "\t" << initY << "\tmoveto" << endl;
angle = initA;
}
Turtle::~Turtle()
{
out << "stroke" << endl;
out << "showpage" << endl;
}
void Turtle::turn(float a)
{
angle += a;
}
void Turtle::draw(float d)
{
float dX, dY;
dX = d * cos(PI * angle / 180);
dY = d * sin(PI * angle / 180);
out << dX << "\t" << dY << "\trlineto" << endl;
}
void Turtle::move(float d)
{
float dX, dY;
dX = d * cos(PI * angle / 180);
dY = d * sin(PI * angle / 180);
out << dX << "\t" << dY << "\trmoveto" << endl;
}
#endif
Okay, so now that you've seen my code, here's my problem:
I want to write the text for every Gosper class object in GosperDriver.cpp into one postscript file. As it is right now, any attempt to do that will result in the previous block of text in the designated output.ps to be overwritten. At the moment, I can only write the text necessary for ONE Gosper class object. I have had to comment out every Gosper object declaration in Gosperdriver.cpp but one, in order to test if my program is working correctly.
In short, I need to write the text necessary to output.ps for every Gosper object in GosperDriver.cpp, but it isn't working because it will only let me write for one at a time. What do I do?
Bonus question about inheritance: right now, my "starting point" for each Gosper drawing keeps being set at x = 0 and y = 0. As seen by the Gosper object declarations, none of the parameters contain 0 for x or y. Something's gone wonky. What's happening?
Thanks in advance to anyone who can answer one or both of these questions! :)
You can use
out.open("output.ps", std::fstream::in | std::fstream::out | std::fstream::app);
to open the file in append mode. Meaning old content will not be overwritten.
You will however need to add something to detect if the header
out << "%!PS-Adobe-2.0" << endl; has already been written. (I assume you need that exactly once per file.)
To avoid opening and closing the file all the time you could also create a separate class that will open the file, initialize it (write the header) and then use this class to write all your contents and close the file afterwards.
For bonus points use RAII to make the class automatically take care of the file.