Never seen this linker error in my life until I started programming PSP homebrew applications. Anyway, I am making an allegro game and I need to fire projectiles or missiles in this case and I need to use a dynamic and generic array. But my linker complains that there is an undefined reference to the new operator. Below will be the whole source code, makefile, and error details.
Error Details:
1>------ Build started: Project: PSP Asteroids, Configuration: Debug Win32 ------
1> psp-g++ -I. -IC:/pspsdk/psp/sdk/include -O2 -G0 -Wall -I. -IC:/pspsdk/psp/sdk/include -O2 -G0 -Wall -fno-exceptions -fno-rtti -D_PSP_FW_VERSION=150 -c -o main.o main.cpp
1> psp-gcc -I. -IC:/pspsdk/psp/sdk/include -O2 -G0 -Wall -D_PSP_FW_VERSION=150 -L. -LC:/pspsdk/psp/sdk/lib main.o -lalleg -lpspgu -lpspirkeyb -lm -lpsppower -lpspaudio -lpsprtc -lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk -lc -lpspnet -lpspnet_inet -lpspnet_apctl -lpspnet_resolver -lpsputility -lpspuser -lpspkernel -o main.elf
1> main.o: In function `std::vector<Missile*, std::allocator<Missile*> >::_M_insert_aux(__gnu_cxx::__normal_iterator<Missile**, std::vector<Missile*, std::allocator<Missile*> > >, Missile* const&)':
1> main.cpp:(.text._ZNSt6vectorIP7MissileSaIS1_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS1_S3_EERKS1_[_ZNSt6vectorIP7MissileSaIS1_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS1_S3_EERKS1_]+0xb8): undefined reference to `operator new(unsigned int)'
1> main.cpp:(.text._ZNSt6vectorIP7MissileSaIS1_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS1_S3_EERKS1_[_ZNSt6vectorIP7MissileSaIS1_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS1_S3_EERKS1_]+0x124): undefined reference to `operator delete(void*)'
1> C:\pspsdk\bin\make: *** [main.elf] Error 1
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Makefile
TARGET = main
OBJS = main.o
CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = PSP Asteroids
LIBS = -lalleg -lpspgu -lpspirkeyb -lm -lpsppower -lpspaudio -lpsprtc
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
main.cpp
#define ALLEGRO_NO_MAGIC_MAIN
#define WIDTH 480
#define HEIGHT 272
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <allegro.h>
#include <math.h>
#include <vector>
PSP_MODULE_INFO("PSP Asteroids", 0, 1, 1);
int check_bb_collision ( BITMAP* spr1, BITMAP* spr2, int x1, int y1, int x2, int y2)
{
int b1_x = x1;
int b2_x = x2;
int b1_y = y1;
int b2_y = y2;
int b1_w = spr1->w;
int b2_w = spr2->w;
int b1_h = spr1->h;
int b2_h = spr2->h;
if ( ( b1_x > b2_x + b2_w - 1 ) || // is b1 on the right side of b2?
( b1_y > b2_y + b2_h - 1 ) || // is b1 under b2?
( b2_x > b1_x + b1_w - 1 ) || // is b2 on the right side of b1?
( b2_y > b1_y + b1_h - 1 ) ) // is b2 under b1?
{
// no collision
return 0;
}
// collision
return 1;
}
//Pass 2 Allegro bitmaps and their respective positions and this function
//returns true if there is a collision and false if theres not.
//The 2 bitmaps must be memory bitmaps of the same color depth.
int check_pp_collision_normal(BITMAP *spr1, BITMAP *spr2, int x1, int y1, int x2, int y2)
{
int dx1, dx2, dy1, dy2; //We will use this deltas...
int fx,fy,sx1,sx2; //Also we will use this starting/final position variables...
int maxw, maxh; //And also this variables saying what is the maximum width and height...
int depth; //This will store the color depth value...
char CHARVAR; //We will use these to store the transparent color for the sprites...
short SHORTVAR;
long LONGVAR;
if( !check_bb_collision(spr1, spr2, x1,y1, x2,y2) ) return 0; //If theres not a bounding box collision, it is impossible to have a pixel perfect collision right? So, we return that theres not collision...
//First we need to see how much we have to shift the coordinates of the sprites...
if(x1>x2) {
dx1=0; //don't need to shift sprite 1.
dx2=x1-x2; //shift sprite 2 left. Why left? Because we have the sprite 1 being on the right of the sprite 2, so we have to move sprite 2 to the left to do the proper pixel perfect collision...
} else {
dx1=x2-x1; //shift sprite 1 left.
dx2=0; //don't need to shift sprite 2.
}
if(y1>y2) {
dy1=0;
dy2=y1-y2; //we need to move this many rows up sprite 2. Why up? Because we have sprite 1 being down of sprite 2, so we have to move sprite 2 up to do the proper pixel perfect collision detection...
} else {
dy1=y2-y1; //we need to move this many rows up sprite 1.
dy2=0;
}
//Then, we have to see how far we have to go, we do this seeing the minimum height and width between the 2 sprites depending in their positions:
if(spr1->w-dx1 > spr2->w-dx2) {
maxw=spr2->w-dx2;
} else {
maxw=spr1->w-dx1;
}
if(spr1->h-dy1 > spr2->h-dy2) {
maxh=spr2->h-dy2;
} else {
maxh=spr1->h-dy1;
}
maxw--;
maxh--;
fy=dy1;
fx=dx1;
dy1+=maxh;
dy2+=maxh;
sx1=dx1+maxw;
sx2=dx2+maxw;
depth=bitmap_color_depth(spr1); //Get the bitmap depth...
if(depth==8) {
CHARVAR=bitmap_mask_color(spr1); //Get the transparent color of the sprites...
for(; dy1>=fy; dy1--,dy2--) { //Go through lines...
for(dx1=sx1,dx2=sx2; dx1>=fx; dx1--,dx2--) { //Go through the X axis...
if((spr1->line[dy1][dx1]!=CHARVAR) && (spr2->line[dy2][dx2]!=CHARVAR)) return 1; //Both sprites don't have transparent color in that position, so, theres a collision and return collision detected!
}
}
} else {
if(depth==16 || depth==15) {
SHORTVAR=bitmap_mask_color(spr1); //Get the transparent color of the sprites...
for(; dy1>=fy; dy1--,dy2--) { //Go through lines...
for(dx1=sx1,dx2=sx2; dx1>=fx; dx1--,dx2--) { //Go through the X axis...
if(( ((short *)spr1->line[dy1])[dx1]!=SHORTVAR) && ( ((short *)spr2->line[dy2])[dx2]!=SHORTVAR)) return 1; //Both sprites don't have transparent color in that position, so, theres a collision and return collision detected!
}
}
} else {
if(depth==32) {
LONGVAR=bitmap_mask_color(spr1); //Get the transparent color of the sprites...
for(; dy1>=fy; dy1--,dy2--) { //Go through lines...
for(dx1=sx1,dx2=sx2; dx1>=fx; dx1--,dx2--) { //Go through the X axis...
if(( ((long *)spr1->line[dy1])[dx1]!=LONGVAR) && ( ((long *)spr2->line[dy2])[dx2]!=LONGVAR)) return 1; //Both sprites don't have transparent color in that position, so, theres a collision and return collision detected!
}
}
} else {
if(depth==24) {
CHARVAR=bitmap_mask_color(spr1)>>16; //if the order is RGB, this will contain B...
SHORTVAR=bitmap_mask_color(spr1)&0xffff; //if the order is RGB, this will contain GR...
for(; dy1>=fy; dy1--,dy2--) { //Go through lines...
for(dx1=sx1,dx2=sx2; dx1>=fx; dx1--,dx2--) { //Go through the X axis...
if( (*((short *)(spr1->line[dy1]+(dx1)*3))!=SHORTVAR) && (spr1->line[dy1][(dx1)*3+2]!=CHARVAR) && (*((short *)(spr2->line[dy2]+(dx2)*3))!=SHORTVAR) && (spr2->line[dy2][(dx2)*3+2]!=CHARVAR) ) return 1; //Both sprites don't have transparent color in that position, so, theres a collision and return collision detected!
//I have tryed to avoid the above multiplications but it seems that GCC optimizes better than I :-))
}
}
}
}
}
}
//If we have reached here it means that theres not a collision:
return 0; //Return no collision.
}
//Finds the magnitude from a point in 2d.
double magnitude(int x, int y)
{
return sqrt((x * x) + (y* y));
}
char* itoa(int val, int base){
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}
// static class that contain special game constants
class Constants
{
public:
static const double PI = 3.14159265358979323846;
static const double PIOVER4 = (3.14159265358979323846 / 4);
static const double TWOPI = (2 * 3.14159265358979323846);
static const double PIOVER2 = (3.14159265358979323846 / 2);
static const unsigned int MAXBULLETS = 5;
};
// Clamp
inline float clamp(float x, float min, float max)
{
return x < min ? min : (x > max ? max : x);
}
// The ship class
class Ship
{
public:
double X;
static const double Y = (272 - 64);
double angle;
void Init(int x)
{
angle = 0;
X = x;
}
void MoveLeft()
{
X -= 2;
}
void MoveRight()
{
X += 2;
}
void Draw(BITMAP* buffer, BITMAP* sprite, int frame)
{
X = clamp(X, 0, 480);
draw_sprite(buffer, sprite, X, Y);
}
};
class Missile
{
private:
static const double angle = (3.14159265358979323846 / 2);
public:
bool Alive;
static const int V = 5;
double X;
double Y;
void Init(bool alive, int x, int y)
{
Alive = alive;
X = x;
Y = y;
}
void Update()
{
X += V * cos(angle);
Y += V * sin(angle);
}
void Kill()
{
Alive = false;
}
void Draw(BITMAP* buffer, BITMAP* sprite)
{
draw_sprite(buffer, sprite, X, Y);
}
};
std::vector<Missile*>* bullets = (std::vector<Missile*>*)malloc(1);
void FireBullet(Ship* s)
{
if (bullets->size() < Constants::MAXBULLETS)
{
Missile* missile = (Missile*)malloc(1);
missile->Init(true, s->X, s->Y);
bullets->push_back(missile);
}
}
void CleanUp()
{
for(unsigned int index = 0; index < bullets->size(); index++)
{
if (bullets->at(index)->Alive == false)
{
bullets->erase(bullets->begin() + index);
}
}
}
void UpdateBullets()
{
for(unsigned int index = 0; index < bullets->size(); index++)
{
if (bullets->at(index)->Y < 0)
{
bullets->at(index)->Update();
}
else
{
bullets->at(index)->Kill();
}
}
}
void DrawBullets(BITMAP* buffer, BITMAP* sprite)
{
for(unsigned int index = 0; index < bullets->size(); index++)
{
if (bullets->at(index)->Alive == true)
{
bullets->at(index)->Draw(buffer, sprite);
}
}
}
//Entry point of the application
int main(void)
{
Ship* s = (Ship*)malloc(1);
int x = (WIDTH / 2) - 64;
allegro_message("Initialzing ship class");
s->Init(x);
int frame = 0;
BITMAP* buffer = NULL;
BITMAP* background = NULL;
BITMAP* ship = NULL;
SceCtrlData pad;
bool done = false;
allegro_message("Initializing Game...");
int rval = allegro_init();
if (allegro_init() != 0)
{
allegro_message("Error initializing Game Because it returned: %i", rval);
return 1;
}
allegro_message("Setting Graphics Mode...Press X To Begin Game");
set_color_depth(32);
int ret = set_gfx_mode(GFX_AUTODETECT,480,272,0,0);
if (ret != 0)
{
allegro_message("Error setting grahpic mode! Because of it returned: %i", ret);
return ret;
}
background = load_bmp("background.bmp", NULL);
ship = load_bmp("ship.bmp", NULL);
BITMAP* m = load_bmp("missile.bmp", NULL);
if (background == NULL || ship == NULL || m != NULL){
allegro_message("Couldn't load one or more sprites...");
return 0;
}
buffer = create_bitmap(WIDTH, HEIGHT);
if (buffer == NULL)
{
allegro_message("Couldn't create buffer!");
return 0;
}
int previousx = 0;
int previousy = 0;
while(!done)
{
sceCtrlReadBufferPositive(&pad, 1);
if (pad.Buttons & PSP_CTRL_START)
{
done = true;
}
else if (pad.Buttons & PSP_CTRL_CROSS)
{
FireBullet(s);
}
else if (pad.Buttons & PSP_CTRL_LEFT)
{
s->MoveLeft();
}
else if (pad.Buttons & PSP_CTRL_RIGHT)
{
s->MoveRight();
}
UpdateBullets();
CleanUp();
clear(buffer);
draw_sprite(buffer, background, 0, 0);
s->Draw(buffer, ship, frame);
DrawBullets(buffer, ship);
masked_blit(buffer, screen, 0, 0, 0, 0, WIDTH, HEIGHT);
if (frame == (60 * 10))
{
frame = 0;
}
frame++;
vsync();
previousx = pad.Lx;
previousy = pad.Ly;
}
allegro_message("Clearing resources!");
clear(buffer);
clear(ship);
clear(background);
clear(screen);
allegro_message("Thank you for playing!");
return 0;
}
END_OF_MAIN()
If this error cannot be fixed is there a work around. Like what can I use that doesn't use the new operator. I mean I use malloc for dynamically allocating everything but the vector template class is somehow using the new operator.
It seems like you are using gcc as a linker wrapper and not g++. Thus, standard C++ runtime is not linked in, and operator new could not be found. You have to either use g++ to link, or specify C++ runtime yourself, usually it is -lstdc++.
Related
I decided to make a multiplayer game in sfml, the map is a text variable
one step lower,! - block with a collider, # - ground.
It looks something like this:
"## !;
! # !;
###;"
I have a special class "Qardrat" that represents a block with a texture, that is, an alternative to a sprite.
class Quardrat {
public:
void spriteSetPosition(int Vx, int Vy) {
sprite.setPosition(Vx, Vy);
}
void LoadTexture(String textureName) {
texture.loadFromFile(textureName);
// RectangleShape tmpSprite(texture);
sprite.setScale(sizeX, sizeY);
sprite.setTexture(&texture);
}
void ShapeMove(int Vx, int Vy) {
sprite.move(Vx, Vy);
//sprite.setPosition(sprite.getPosition().x+Vx, sprite.getPosition().y+Vy);
std::cout << "Сдвинулся на " << Vx << "По x" << std::endl;
}
Quardrat(float x = 0, float y = 0, float sx = 1, float sy = 1, String textureName = "player.png") {
LoadTexture(textureName);
sizeX = sx;
sizeY = sy;
sprite.setPosition(x, y);
sprite.setSize(Vector2f(sx, sy));
}
sf::RectangleShape GetShape() {
return sprite;
}
void DrawShape() {
::window.draw(sprite);
}
float GetSizeX() {
return sizeX;
}float GetSizeY() {
return sizeY;
}
private:
Texture texture;
std::string texutreName = "player.png";
float sizeX = 10;
float sizeY = 10;
//Sprite sprite;
RectangleShape sprite;
};
It is declared as follows: x position, y position, height, width, texture name.
To draw objects, 3 cities are used, which are placed in the square classes:
sloi0, sloi1, player /
here is the drawing code
void DrawOnDisplay(const std::vector<std::reference_wrapper<Quardrat>>& a) {//РИСОВАНИЕ
for (Quardrat i : sloi0)
i.DrawShape();
//::window.draw(i.GetShape());
for (Quardrat i : sloi1)
i.DrawShape();
// ::window.draw(i.GetShape());
for (Quardrat i : a) {
i.DrawShape();
// ::window.draw(i.GetShape());
}
}
And I'll leave the card reading code here, just in case:
for (char block : map) {
if (block == '#') {
Quardrat bl = Quardrat(BlockPosX * StandartBlockSize, BlockPosY * StandartBlockSize, StandartBlockSize, StandartBlockSize);
sloi0.push_back(bl); BlockPosX++;
// }
if (block == '!') {
Quardrat bl = Quardrat(BlockPosX * StandartBlockSize, BlockPosY * StandartBlockSize,
StandartBlockSize / 10, StandartBlockSize / 10, "block.png");
sloi0.push_back(bl); BlockPosX++;
collisions.push_back(bl);
}
if (block == ';') {
BlockPosY++;
BlockPosX = 0;
}
}
And here's the problem - from all the blocks of the map, a texture appears only for one, for all the rest - a white square.
So I'm trying to call a member function pointer in the code below, using a map of member function pointers of typedef void (CommandHandler::*pfunc)(std::vector<String>&)
However, I'm having issues getting the syntax to work because I get the following error:
expected unqualified-id before '(' token
Note that this is Arduino, and the ArduinoSTL supports most STL calls.
This line fails, and commenting out this line results in code that indeed compiles.
((this).(*(this.cmd_func)))(parses);
I've tried different syntaxes that I've seen online, eg https://isocpp.org/wiki/faq/pointers-to-members.
Even in that syntax it resulted in errors. (eg using the macro below still resulted in errors)
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
I have a feeling it has something to do with my typedef type and the compiler spitting out an error that doesn't make sense (immediately) when looking at the code. Can anyone help me understand why this code fails? Thanks!
Full file below
#include <ArduinoSTL.h>
#include<map>
#include <vector>
#include <Adafruit_NeoPixel.h>
#include <iostream>
#include <string>
#include <EEPROM.h>
#define LED_PIN 4
#define LED_COUNT 12
#define MY_ROLE 0
//#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) //This call doesn't work in Arduino
#define X_ADDR 0
#define Y_ADDR 1
#define MY_ROLE 2
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
class CommandHandler{
typedef void (CommandHandler::*pfunc)(std::vector<String>&);
CommandHandler::CommandHandler(){
x = EEPROM.read(X_ADDR);
y = EEPROM.read(Y_ADDR);
role_id = MY_ROLE;
init_commands_with_args();
}
CommandHandler::CommandHandler(int x, int y, int role_id){
this->x = x;
this->y = y;
this->role_id = role_id;
init_commands_with_args();
}
public:
int x, y, role_id;
std::map<String, pfunc> commandsTable;
void set_red(){show_led_int(255,0,0);}
void set_green(){show_led_int(0,255,0);}
void set_blue(){show_led_int(0,0,255);}
void set_purple(){show_led_int(255, 0, 255);}
void set_yellow(){show_led_int(255, 255, 0);}
void set_cyan(){show_led_int(0,255,255);}
void set_white(){show_led_int(255,255,255);}
void set_none(){show_led_int(0,0,0);}
void init_commands_with_args(){
commandsTable["a"] = &show_led;
//commandsTable["b"] = &blink_color;
//commandsTable["c"] = &theaterChase;
//commandsTable["d"] = &rainbow;
//commandsTable["e"] = &theaterChaseRainbow;
return;
}
void handle_command(std::string input, std::string delimiter = "/"){
if (input.size() == 1){
switch(input[0]){
case 'R':
CommandHandler::set_red();
case 'B':
CommandHandler::set_blue();
case 'G':
CommandHandler::set_green();
case 'W':
CommandHandler::set_white();
case 'P':
CommandHandler::set_purple();
case 'C':
CommandHandler::set_cyan();
case 'Y':
CommandHandler::set_yellow();
case 'N':
CommandHandler::set_none();
}
}
else{
std::vector<String> parses; // 10 maximum args
size_t pos = 0; size_t i = 0;
String token;
//std::string tokens = s.substr(0, s.find(delimiter));
while ((pos = input.find(delimiter)) != std::string::npos) {
token = String(input.substr(0, pos).c_str());
//std::cout << token << std::endl;
parses.push_back(token);
input.erase(0, pos + delimiter.length());
i++;
}
//Parses is now an array of strings.
pfunc cmd_func = commandsTable[parses[0]];
parses.erase(parses.begin());
((this).(*(this.cmd_func)))(parses); //This line fails no matter what I try to do. //Expected unqualified-id before '(' token
//I want to call the function of this instance that is in commandsTable, with arguments defined in the vector parses.
//The first element of the vector which is later erased is the function in commandsTable that is mapped
//Other elements are arguments in the string.
}
}
void blink(){
delay(0.5*role_id);
this->show_led_int(255, 255, 255);
delay(0.5);
this->show_led_int(0, 0, 0);
}
//void blink_color(int r, int b, int g){
void blink_color(std::vector<String> & input){
int r = String(input[0].c_str()).toInt();
int b = String(input[1].c_str()).toInt();
int g = String(input[2].c_str()).toInt();
uint32_t mycolor = strip.Color(r, b, g);
delay(0.5*role_id);
this->show_led_int(r, b, g);
delay(0.5);
this->show_led_int(0, 0, 0);
}
//void show_led(int r, int b, int g){
void show_led(std::vector<String> & input){
int r = String(input[0].c_str()).toInt();
int b = String(input[1].c_str()).toInt();
int g = String(input[2].c_str()).toInt();
uint32_t mycolor = strip.Color(r, b, g);
strip.setPixelColor(0, mycolor);
strip.setPixelColor(1, mycolor);
strip.setPixelColor(2, mycolor);
strip.setPixelColor(3, mycolor);
strip.setPixelColor(4, mycolor);
strip.setPixelColor(5, mycolor);
strip.setPixelColor(6, mycolor);
strip.setPixelColor(7, mycolor);
strip.setPixelColor(8, mycolor);
strip.setPixelColor(9, mycolor);
strip.setPixelColor(10, mycolor);
strip.setPixelColor(11, mycolor);
strip.show();
}
void show_led_int(int r, int b, int g){
uint32_t mycolor = strip.Color(r, b, g);
strip.setPixelColor(0, mycolor);
strip.setPixelColor(1, mycolor);
strip.setPixelColor(2, mycolor);
strip.setPixelColor(3, mycolor);
strip.setPixelColor(4, mycolor);
strip.setPixelColor(5, mycolor);
strip.setPixelColor(6, mycolor);
strip.setPixelColor(7, mycolor);
strip.setPixelColor(8, mycolor);
strip.setPixelColor(9, mycolor);
strip.setPixelColor(10, mycolor);
strip.setPixelColor(11, mycolor);
strip.show();
}
//void colorWipe(uint32_t color, int wait) {
void colorWipe(std::vector<String> & input){
uint32_t color = String(input[0].c_str()).toInt();;
int wait = String(input[0].c_str()).toInt();;
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
//void theaterChase(uint32_t color, int wait) {
void theaterChase(std::vector<String> & input){
uint32_t color = String(input[0].c_str()).toInt();
int wait = String(input[1].c_str()).toInt();
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
//void rainbow(int wait) {
void rainbow(std::vector<String> & input){
int wait = String(input[0].c_str()).toInt();
for(long firstPixelHue = 0; firstPixelHue < 5*65536; firstPixelHue += 256) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
// Offset pixel hue by an amount to make one full revolution of the
// color wheel (range of 65536) along the length of the strip
// (strip.numPixels() steps):
int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
// strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
// optionally add saturation and value (brightness) (each 0 to 255).
// Here we're using just the single-argument hue variant. The result
// is passed through strip.gamma32() to provide 'truer' colors
// before assigning to each pixel:
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
//void theaterChaseRainbow(int wait) {
static void theaterChaseRainbow(std::vector<String> & input){
int wait = String(input[0].c_str()).toInt();
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) { // Repeat 30 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in increments of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
void updateRole(std::vector<String> & input){
this->role_id = input[0].toInt();
}
void updateLoc(std::vector<String> & input){
this->x = input[0].toInt();
this->y = input[1].toInt();
EEPROM.write(X_ADDR, this->x);
EEPROM.write(Y_ADDR, this->y);
}
};
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
Calling a pointer-to-member can get a little complicated looking. Since this is a pointer, and CALL_MEMBER_FN expects a reference, you'd use the macro as
CALL_MEMBER_FN(*this, this->cmd_func)(parses);
Or, without the macro,
(this->*(this->cmd_func))(parses);
UPDATE
I see, providing code partly doesn't decide the problem. There are a lot of files, so I'll provide all aplication via GitHub for anybody would like to try to decide this problem:
https://github.com/johnydominus/CrimsonLikeGameSMFL
Sorry in advance for my English and programming knowledge. I'm newbie.
I'm making a 2D game using C++ and SFML SDK. The game is similar to CrimsonLand (2003): player should be walking on map and shooting monsters, while they trying to reach him.
For the moment player is walking and monsters are chasing him, but only if their direction is left or up. If needed direction is right or down - they don't move. Monsters just staying and staring at players direction. And player just doesn't move when right or down buttons pressed.
I've implement 2 movement coordinates systems - relative to map (to handle game events, like intersection monsters with bullets) and relative to player (to center "camera" on player). Movement written to map coordinates first, then it is transformed to player relative coordinates. Hence, drawing is using player relative coordinates. However, it doesn't look like that problem is in drawing.
Input is working - I've tried to change movement assignment (just for check) and set to move left when right button pressed and up when down button pressed - and it worked: player moved up both by up and down buttons and moved left by left and right buttons.
I'll try to delete all strings, that don't relate to the problem. But due to fact, that I don't have a clear idea what is wrong - there will be quite a lot of code.
Map, monster and player headers, and .cpp files - declaration and definition of game objects.
Engine header and .cpp - declaration and definition of engine, that handles objects interaction.
Input and update .cpp's - definition of Engine methods, that handle respectively input from keyboard and updating objects position and state.
player.h
class Player :
public Object
{
private:
std::vector<float> mapSize{0,0};
int speed = 1;
POINT prevPosition;
std::vector<float> relatMovement{ 0,0 };
bool leftPressed;
bool rightPressed;
bool upPressed;
bool downPressed;
public:
POINT Position;
POINT relatPosition;
void moveLeft();
void moveRight();
void moveUp();
void moveDown();
void stopLeft();
void stopRight();
void stopUp();
void stopDown();
void update(float elapsedTime);
};
player.cpp
void Player::moveLeft()
{
leftPressed = true;
}
void Player::moveRight()
{
rightPressed = true;
}
void Player::moveUp()
{
upPressed = true;
}
void Player::moveDown()
{
downPressed = true;
}
void Player::stopLeft()
{
leftPressed = false;
}
void Player::stopRight()
{
rightPressed = false;
}
void Player::stopUp()
{
upPressed = false;
}
void Player::stopDown()
{
downPressed = false;
}
void Player::update(float elapsedTime)
{
if (rightPressed)
Position.x += speed * elapsedTime;
if (leftPressed)
Position.x -= speed * elapsedTime;
if (upPressed)
Position.y -= speed * elapsedTime;
if (downPressed)
Position.y += speed * elapsedTime;
relatMovement[0] = Position.x - prevPosition.x;
relatMovement[1] = Position.y - prevPosition.y;
prevPosition = Position;
}
monster.h
class Monster :
public Object
{
private:
float pathLength;
Player* thePlayer;
Map* theMap;
POINT playerPosition;
POINT playerRelatPosition;
POINT nextStep;
std::vector<float> playerRelatMovement{0,0};
std::vector<float> direction{ 0,0 };
std::vector<float> vSpeed{ 0,0 };
public:
POINT Position;
POINT relatPosition;
POINT checkUpdate(float elapsedTime);
void update(float elapsedTime, POINT position);
};
monster.cpp
POINT Monster::checkUpdate(float elapsedTime)
{
nextStep = Position;
playerPosition = *(thePlayer->getPosition());
direction[0] = playerPosition.x - Position.x;
direction[1] = playerPosition.y - Position.y;
pathLength = sqrt(pow(direction[0], 2) + pow(direction[1], 2));
direction[0] /= pathLength;
direction[1] /= pathLength;
vSpeed[0] = ((float)direction[0] * (float)speed)/10.0;
vSpeed[1] = ((float)direction[1] * (float)speed)/10.0;
nextStep.x += vSpeed[0];
nextStep.y += vSpeed[1];
return nextStep;
}
void Monster::update(float elapsedTime, POINT aNextStep)
{
Position = aNextStep;
playerPosition = *(thePlayer->getPosition());
playerRelatPosition = *(thePlayer->getRelatPosition());
relatPosition.x = playerRelatPosition.x + (Position.x - playerPosition.x);
relatPosition.y = playerRelatPosition.y + (Position.y - playerPosition.y);
shape.left = Position.x - (size[0] / 2);
shape.right = Position.x + (size[0] / 2);
shape.top = Position.y - (size[1] / 2);
shape.bottom = Position.y + (size[1] / 2);
}
map.h
class Map:
public Object
{
private:
std::vector<float> relatMovement{0,0};
std::vector<float> size{0,0};
Player* thePlayer;
public:
POINT Position;
POINT relatPosition;
void update();
};
map.cpp
Map::Map()
{
Position.x = 0;
Position.y = 0;
}
void Map::update()
{
relatMovement = *(thePlayer->getRelatMovement());
relatPosition.x -= relatMovement[0];
relatPosition.y -= relatMovement[1];
}
Engine.h
class Engine
{
private:
Player thePlayer;
Map theMap;
Monster* allMonsters;
int mapXstart=0, mapYstart=0, ammoNumberStart=0, enemiesNumberStart=0;
void input();
void update(float timeInSeconds);
void draw();
void setWindowSize(int mapX, int mapY);
void setMapSize(float mapWidth, float mapHeight);
public:
void start();
};
Engine.cpp
Engine::Engine()
{
//setting map sprites
a = ((mapY+windowY) / theMap.mSprite.getTexture()->getSize().y) + 1;
b = ((mapX+windowX) / theMap.mSprite.getTexture()->getSize().x) + 1;
mapSprites = new sf::Sprite*[a];
for (i = 0; i < a; i++) {
mapSprites[i] = new sf::Sprite[b];
for (j = 0; j < b; j++) {
mapSprites[i][j].setTexture(*theMap.mSprite.getTexture());
}
}
//setting window
mWindow.create(sf::VideoMode(windowX, windowY), "CrimsonLikeGame", sf::Style::Default);
//setting game objects
//map
int mapRelX, mapRelY;
mapRelX = (windowX / 2) - (mapX / 2);
mapRelY = (windowY / 2) - (mapY / 2);
theMap.setRelativePosition(mapRelX, mapRelY);
theMap.setSize(mapX, mapY);
theMap.setPlayer(&thePlayer);
//player
thePlayer.setPosition(mapX/2,mapY/2);
thePlayer.setRelativePosition(windowX / 2, windowY / 2);
thePlayer.setMapSize(mapX, mapY);
//monsters
allMonsters = new Monster[enemiesNumber];
for (i = 0; i < enemiesNumber; i++) {
allMonsters[i].setPlayer(&thePlayer);
allMonsters[i].setMap(&theMap);
}
}
void Engine::start()
{
sf::Clock clock;
//game loop
while (mWindow.isOpen()) {
sf::Time dt = clock.restart();
float dtAsSeconds = dt.asSeconds();
input();
update(dtAsSeconds);
draw();
}
}
input.cpp
void Engine::input() {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
mWindow.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
thePlayer.moveLeft();
}
else {
thePlayer.stopLeft();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
thePlayer.moveRight();
}
else {
thePlayer.stopRight();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
thePlayer.moveUp();
}
else {
thePlayer.stopUp();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
thePlayer.moveDown();
}
else {
thePlayer.stopDown();
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
mouseButtonPressed = true;
}
else {
mouseButtonPressed = false;
}
}
update.cpp
void Engine::update(float timeInSeconds) {
if (thePlayer.isAlive()&&enemiesAlive) {
thePlayer.update(timeInSeconds);
theMap.update();
//Writing down, where each monster is going to go by it's next step
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()) {
enemiesNextSteps[i] = allMonsters[i].checkUpdate(timeInSeconds);
}
}
//cheking - does anybody is going to collide
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()) {
int j;
for (j = 0; j < enemiesNumber; j++) {
if (j == i)
continue;
else {
if ((((allMonsters[i].shape.left <= allMonsters[j].shape.right) && (allMonsters[i].shape.left >= allMonsters[j].shape.left)) || ((allMonsters[i].shape.right <= allMonsters[j].shape.right) && (allMonsters[i].shape.right >= allMonsters[j].shape.left))) && (((allMonsters[i].shape.bottom >= allMonsters[j].shape.top) && (allMonsters[i].shape.bottom <= allMonsters[j].shape.bottom)) || ((allMonsters[i].shape.top >= allMonsters[j].shape.top) && (allMonsters[i].shape.top <= allMonsters[j].shape.bottom)))) {
monstersCollide[i] = true;
}
}
}
}
}
//updating each alive monster position without collisions
for (i = 0; i < enemiesNumber; i++) {
if (allMonsters[i].isAlive()/*&&!monstersCollide[i]*/) {
allMonsters[i].setPosition(enemiesNextSteps[i]);
allMonsters[i].update(timeInSeconds, enemiesNextSteps[i]);
}
}
}
else {
//if player is dead - restart the game
thePlayer.setAlive(true);
for (i = 0; i < enemiesNumber; i++) {
allMonsters[i].setAlive(true);
}
}
}
I was trying to figure it out half a day. Hope you can help me with that problem.
Okay. I've actually built and ran this code, and the root cause for your movement problem is using integers for your coordinates, and ensuing assymetry:
if (rightPressed)
Position.x += speed * elapsedTime;
if (leftPressed)
Position.x -= speed * elapsedTime;
Those two seem pretty equal at first, but when you consider what really happens, they differ slightly. Because your speed is relatively low (1.0), and so is your elapsed time (e.g. ~0.016 for one frame), the differences end up being less by one. To understand what happens next, you need to look at type conversions.
The statements are actually equivalent to:
Position.x = Position.x + (speed * elapsedTime);
Because speed and elapsedTime are floating point numbers, Position.x gets promoted to a float as well. Then the fraction is either added and subtracted, and then the result is converted back to an integer.
In case of moving left, the number e.g. 100 is converted to 100.0, then 0.016 gets subtracted, resulting in 99.984. Then, integer conversion removes the decimal part, resulting in the value of 99 and an observable change in your player's position.
In the case of moving right, we do the same, but we end up with a value of 100.016 instead. This converted back to integer results with a value of 100 again.
To fix this, the easiest solution is to make the player's position use floats as well. Then the small changes will be properly accumulated. You might observe that the player moves way slower than you'd expect at first, because the integer clamping effect will dissappear; setting the speed to 60 should get you more or less back where it was.
I am using OpenCV 2.4.10 with Visual Studio 2013 for my code. But I am getting the following linking error:
1>Pathfinding.obj : error LNK2019: unresolved external symbol "public:
class cv::Vec & __cdecl cv::Mat::at >(int,int)"
(??$at#V?$Vec#E$02#cv###Mat#cv##QEAAAEAV?$Vec#E$02#1#HH#Z) referenced
in function "private: struct Pathfinding::Point2A * __cdecl
Pathfinding::GetNeighbors(struct Pathfinding::Point2A,int &)"
(?GetNeighbors#Pathfinding##AEAAPEAUPoint2A#1#U21#AEAH#Z)
1>C:\Users\ysingh\Documents\DstarLite\OpenCV\Astar\x64\Debug\Astar.exe
: fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Here is the header file (please see struct Point2A in class definition) where the above error is referring to:
#include<opencv2\core\core.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<string>
class Pathfinding
{
private :
//Two dimensional , integer -based point structure , contains additional variables for pathfinding calculation
**struct Point2A**
{
// x, y the coordinates of the point
//dir is the direction from the previous point . see directions coding below
int x, y, dir;
//level: the cost of route from start to this point
//fscore: the essence of the A* algorithm, value is : [level] + [in air distance from destination] * astar_weight
float fScore, level;
//Constructors
Point2A() : x(0), y(0), fScore(0), dir(0){};
Point2A(int _x, int _y, float _level = 0.f, int _dir = 0) :x(_x), y(_y), level(_level), fScore(0), dir(_dir) {};
//== operator overload
bool operator == (const Point2A other);
};
//CompByPos : struct used in the stl map<Point2A, Point2A> during the pathfinding
//it only contains a comparator function
//we need this, because every point is unique by position, but not by fscore
struct CompByPos
{
bool operator()(const Point2A a, const Point2A b) const;
};
//CompByFScore : contains a comparating function, which works by fscore
//it gives priority for the smaller fScore
//used in stl priority_queue<Point2A>
struct CompByFScore
{
bool operator()(const Point2A a, const Point2A b);
};
//mapimg is the map got, pathmap is the same, but the pixels of the path are colored
//pathmap is only valid after calculate path
//blurmap is matimg blurred with opencv function, its used in keeping away from walls
cv::Mat mapimg, pathmap, blurmap;
//astar_weight is the multiplier of A* coefficient
//wall_weight is used in keeping away from walls features
float astar_weight, wall_weight;
//no comment
Point2A start, dest;
//daigonal decides if a pixel (which is a node) has 4 or 8 neighbours
//see direction coding below
//calculated decides if the Pathfinding object has valid path for current map and settings
bool diagonal, calculated;
//mrows and mcols refers to the size of mapimg
//blursize is used in avaoiding wall avoidance feature
int mrows, mcols, blur_size;
//stores the list of directions for the path
std::string dir;
//calculated Eucledian Distance between two points a and b
float Distance(Point2A a, Point2A b);
//returns an array of the points surrounding point p
//the length of the array is not constant, because the function performs
//OnMap checks too. use arraySize ref variable to get the size of the array returned
Point2A* GetNeighbors(Point2A p, int& arraySize);
// Function sets default values
void InitValues();
//Checks if point p is wall
//Class support black and white maps, where black pixels are wall
bool IsWall(Point2A p);
//Function decides if coordinates of this point are on map or not
bool OnMap(int x, int y);
public:
enum ErrorCodes
{
NoError = 0,
NoMap,
StartIsWall,
DestIsWall,
NoPath,
AlreadyCalculated
};
static const int diagonalDirX[];
static const int diagonalDirY[];
static const int nonDiagonalDirX[];
static const int nonDiagonalDirY[];
//constructor :sets default values diagonal = true, astar coefficient 0.3
Pathfinding();
//constructor, argument map is the map on which algorithm is implemented
Pathfinding(cv::Mat map, bool _diagonal = true);
//Set OpenCV Mat image as the map
void SetMap(cv::Mat map);
////sets the A* pathfinding coefficient. 0.f means Dijkstra's algorithm, anything else is A* (positive values recommended).
//The bigger the value, the more the algorithm steers towards the destination
//but setting it too high can result in suboptimal path
//after changing that, have to call CalculatePath again
void SetAWeight(float weight);
//if set to true, each pixel has 8 connected neighbor, else only 4 - see GetDirections() comment
//after changing that, have to call CalculatePath again
void SetDiagonal(bool _diagonal);
//sets the value of how much the algorithm tries to avoid going near walls.
//weight: the amount the walls push away the route. default 10.f
//0.f disables the feature
//avoidZoneLevel: the size of the zone surrounding the walls, in which the upper effect works. default: 5
void SetWallWeight(float weight, int avoidZoneLevel);
//sets the start point. the coordinate system is the OpenCV/image default, the origin is the upper left corner of the image.
//start and destination points have to be set after the map image!
void SetStart(int x, int y);
void SetDestination(int x, int y);
//returns the map, on which the calculated path is marked red
//call this after CalculatePath(), otherwise returns empty map
cv::Mat GetPathMap();
// returns a std::string of numbers, which represent the directions along the path.Direction coding(relative to p) :
//call after CalculatePath()
//if diagonal is set to true if diagonal == false
// [0] [1] [2] [3]
// [3] [p] [4] [2] [p] [0]
// [5] [6] [7] [1]
std::string GetDirections();
//evaluates the algorithm. It's a separate function because it takes some time
//check out the ErrorCodes enum to decode the returned values
ErrorCodes CalculatePath();
};
I am also attaching the .cpp for this class
#include "Pathfinding.h"
bool Pathfinding::Point2A::operator==(const Point2A other) {
return x == other.x && y == other.y;
}
bool Pathfinding::CompByPos::operator()(const Point2A a, const Point2A b) const
{
if (a.x == b.x)
return a.y > b.y;
else
return a.x > b.x;
}
bool Pathfinding::CompByFScore::operator()(const Point2A a, const Point2A b)
{
return a.fScore > b.fScore;
}
float Pathfinding::Distance(Point2A a, Point2A b)
{
float x = static_cast<float>(a.x - b.x);
float y = static_cast<float>(a.y - b.y);
return sqrtf(x*x + y*y);
}
Pathfinding:: Point2A* Pathfinding::GetNeighbors(Point2A p, int& arraySize)
{
arraySize = 0;
uchar size;
if (diagonal)
size = 8;
else
size = 4;
Point2A* ret = new Point2A[size];
for (int i = 0; i < size; i++) {
int x, y;
if (diagonal)
{
x = p.x + diagonalDirX[i];
y = p.y + diagonalDirY[i];
}
else
{
x = p.x + nonDiagonalDirX[i];
y = p.y + nonDiagonalDirY[i];
}
if (!OnMap(x, y))
continue;
float level = p.level + 1.f + (255 - blurmap.at<cv::Vec3b>(y, x)[2]) / 255.f * wall_weight;
Point2A n = Point2A(x, y, level, i);
if (diagonal && (i == 0 || i == 2 || i == 5 || i == 7))
n.level += 0.414213f;
ret[arraySize] = n;
arraySize++;
}
return ret;
}
void Pathfinding::InitValues()
{
astar_weight = 0.3f;
wall_weight = 10.f;
blur_size = 11;
diagonal = true;
calculated = false;
}
bool Pathfinding::IsWall(Point2A p)
{
if (mapimg.at<cv::Vec3b>(p.y, p.x) == cv::Vec3b(0, 0, 0))
return true;
return false;
}
bool Pathfinding::OnMap(int x, int y)
{
if (x >= 0 && y >= 0 && x < mcols && y < mrows)
return true;
return false;
}
const int Pathfinding::diagonalDirX[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
const int Pathfinding::diagonalDirY[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
const int Pathfinding::nonDiagonalDirX[] = { 1, 0, -1, 0 };
const int Pathfinding::nonDiagonalDirY[] = { 0, 1, 0, -1 };
Pathfinding::Pathfinding()
{
InitValues();
}
Pathfinding::Pathfinding(cv::Mat map, bool _diagonal)
{
InitValues();
SetMap(map);
diagonal = _diagonal;
}
void Pathfinding::SetMap(cv::Mat map)
{
if (!map.empty())
{
mapimg = map;
calculated = false;
mrows = map.rows;
mcols = map.cols;
GaussianBlur(mapimg, blurmap, cv::Size(blur_size, blur_size), 0);
}
}
void Pathfinding::SetAWeight(float weight)
{
if (astar_weight != weight)
{
astar_weight = weight;
calculated = false;
}
}
void Pathfinding::SetDiagonal(bool _diagonal)
{
if (diagonal != _diagonal)
{
diagonal = _diagonal;
calculated = false;
}
}
void Pathfinding::SetWallWeight(float weight, int avoidZoneLevel)
{
if (wall_weight == weight && blur_size == 2 * avoidZoneLevel + 1)
return;
wall_weight = weight;
if (avoidZoneLevel >= 0)
blur_size = 2 * avoidZoneLevel + 1;
calculated = false;
}
void Pathfinding::SetStart(int x, int y)
{
if (!mapimg.empty())
{
if (OnMap(x, y))
{
start = Point2A(x, y);
calculated = false;
}
}
}
void Pathfinding::SetDestination(int x, int y)
{
if (!mapimg.empty())
{
if (OnMap(x, y))
{
dest = Point2A(x, y);
calculated = false;
}
}
}
cv::Mat Pathfinding::GetPathMap()
{
if (calculated) return pathmap;
else return cv::Mat();
}
std::string Pathfinding::GetDirections()
{
if (calculated) return dir;
else return std::string();
}
Pathfinding::ErrorCodes Pathfinding::CalculatePath()
{
if (calculated)
return AlreadyCalculated;
if (mapimg.empty())
return NoMap;
if (IsWall(start))
return StartIsWall;
if (IsWall(dest))
return DestIsWall;
dir = std::string();
mapimg.copyTo(pathmap);
int **closedSet = new int*[mrows];
float **openSet = new float*[mrows];
for (int i = 0; i < mrows; i++) {
closedSet[i] = new int[mcols];
openSet[i] = new float[mcols];
for (int j = 0; j < mcols; j++) {
closedSet[i][j] = 0;
openSet[i][j] = -1.0f;
}
}
std::priority_queue<Pathfinding::Point2A, std::vector<Point2A>, CompByFScore> openSetQue[2];
int osq = 0;
std::map <Pathfinding::Point2A, Pathfinding::Point2A, CompByPos> cameFrom;
start.fScore = Distance(start, dest);
openSetQue[osq].push(start);
openSet[start.y][start.x] = 0.0f;
while (openSetQue[osq].size() != 0) {
Point2A current = openSetQue[osq].top();
if (current == dest) {
while (cameFrom.size() != 0) {
pathmap.at<cv::Vec3b>(current.y, current.x) = cv::Vec3b(0, 0, 255);
dir = std::to_string(current.dir) + dir;
auto it = cameFrom.find(current);
Point2A keytmp = current;
if (it == cameFrom.end()) {
for (int i = 0; i < mrows; i++) {
delete openSet[i];
delete closedSet[i];
}
delete openSet;
delete closedSet;
calculated = true;
dir = dir.substr(1, dir.length() - 1);
return NoError;
}
current = cameFrom[current];
cameFrom.erase(keytmp);
}
}
openSetQue[osq].pop();
closedSet[current.y][current.x] = 1;
int arraySize;
Point2A *neighbors = GetNeighbors(current, arraySize);
for (int i = 0; i < arraySize; i++) {
Point2A neighbor = neighbors[i];
if (closedSet[neighbor.y][neighbor.x] == 1)
continue;
if (IsWall(neighbor)) {
closedSet[neighbor.y][neighbor.x] = 1;
continue;
}
float ngScore = neighbor.level;
if (openSet[neighbor.y][neighbor.x] == -1.0f || ngScore < openSet[neighbor.y][neighbor.x]) {
cameFrom[neighbor] = current;
neighbor.fScore = ngScore + Distance(neighbor, dest) * astar_weight;
if (openSet[neighbor.y][neighbor.x] == -1.0f) {
openSet[neighbor.y][neighbor.x] = ngScore;
openSetQue[osq].push(neighbor);
}
else {
openSet[neighbor.y][neighbor.x] = ngScore;
while (!(neighbor == openSetQue[osq].top())) {
openSetQue[1 - osq].push(openSetQue[osq].top());
openSetQue[osq].pop();
}
openSetQue[osq].pop();
if (openSetQue[osq].size() >= openSetQue[1 - osq].size()) {
osq = 1 - osq;
}
while (!openSetQue[osq].empty()) {
openSetQue[1 - osq].push(openSetQue[osq].top());
openSetQue[osq].pop();
}
osq = 1 - osq;
openSetQue[osq].push(neighbor);
}
}
}
delete neighbors;
}
return NoPath;
}
Here is my main file .cpp too :
#include"Pathfinding.h"
#include<opencv2\highgui\highgui.hpp>
#include<iostream>
Pathfinding pathfinding;
cv::Mat mapimg;
void DisplayMap()
{
cv::Mat tmp;
cv::imshow("Path", tmp);
}
int main()
{
//Open and load the map
mapimg = cv::imread("test.png");
pathfinding.SetMap(mapimg);
pathfinding.SetWallWeight(0.f, 0);
pathfinding.SetStart(1, 1);
pathfinding.SetDestination(39, 53);
pathfinding.SetDiagonal(false);
DisplayMap();
}
I think I am using Pathfinding class twice in the definition of the functions in .cpp ( i.e. Line 29 in .cpp file > Pathfinding:: Point2A* Pathfinding::GetNeighbors(Point2A p, int& arraySize)
My intention is not to throw a bunch of codes at the people but to give them an complete picture for the problem so that people can provide me some useful suggestions. My apologies for this.
My deadlines are near and I am constrained with time. Can someone suggest me some solutions.
I assume your project settings are the problem for this (your write you did a working minimalistic example, so you indeed use right libs and includes).
Please check what the include and lib paths evaluate to (check this inside the configuration site). Maybe you see they are relative paths or a makro was set wrong.
Usually, an "UNRESOLVED EXTERNAL" error means you did not link the right lib (32/64 debug/release these are 4 different combinations!) or the path to the lib is wrong.
See this answer,
If you DID explicitly set up linking with all the necessary libraries,
but linking errors still show, you might be mixing up 64/32 bit
libraries and application.
BUILD -> Configration Manager. check 'platform' is 'x64'
Check that your Project -> Properties -> VC++ Directories -> Library Directories, includes the path where the OpenCV libraries are
And Linker -> General -> Aditional Library Directories
C:\opencv\build\x64\vc11\lib
(on a 64-bit machine running VS2012, it will vary on other setups).
I'm a bit of a newcomer to programming and C++, and learning how to program games with Allegro 5. One of the projects I've set for myself is to clean up a tutorial source code of Pong that I found here: http://www.cppgameprogramming.com/newforums/viewtopic.php?f=5&t=1991
However, I've run into a problem. The compiler generates an error I don't entirely understand, and none of my research is panning out. The error is:
insufficient contextual information to determine type
The closest I found on the internet was this page: http://bytes.com/topic/c/answers/138897-error-insufficient-contextual-information-determine-type which helped me narrow down that the problem is in the class declarations. However, the solution provided there doesn't exactly apply to me, since the class constructors here take parameters. The question previously asked here doesn't seem to apply to my situation, either, since it used file output and templates, neither of which I'm using.
I've posted a large chunk of my program below, with the error-generating parts marked out with commented stars to make them easy to find, I hope. However, I've left in a lot of the rest of the code on the off-chance that it's somewhere else.
As a heads up: there might be bits of code you don't recognize from allegro 5, such as alObject.paint(255,255,255). That's me consolidating some of the allegro objects and functions into their own class to make it a bit easier on me, the source of which I'm not including here since the compiler doesn't generate errors with them.
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include "allegro.h"
struct CBox{
CBox(int _x, int _y, int _w, int _h):x(_x),y(_y),w(_w),h(_h){}
CBox(const CBox& other){
x = other.x;
y = other.y;
w = other.w;
h = other.h;
}
bool collides(const CBox& other){
return not(other.x + other.w < x or other.y + other.h < y or other.x > x + y or other.y > y + h);
}
int x;
int y;
int w;
int h;
};
class CPlayer{
private:
int score;
CBox box;
ALLEGRO_COLOR color;
double mov_y;
void testBounds(CBox&);
public:
CPlayer(CBox p, ALLEGRO_COLOR col):box(p),color(col){mov_y = 0.0;}
void setScore(int new_s){score=new_s;}
int getScore(){return score;}
void setBox(const CBox& b){box=b;}
CBox getBox(){return box;}
void setXYMovement(double new_my){mov_y=new_my;}
double getXYMovement(){return mov_y;}
void move(CBox& bounds);
void draw(){
al_draw_filled_rectangle(box.x, box.y, box.x + box.w, box.y + box.h, color);
}
};
class CBall{
private:
CBox box;
ALLEGRO_COLOR color;
double mov_y;
double mov_x;
int last_touch;
void testCollision(CBox&, const CBox&, CPlayer*);
int testBounds(CBox&, const CBox&);
public:
CBall(CBox p, ALLEGRO_COLOR col):box(p),color(col),last_touch(3){}
void setXYMovement(double new_mx, double new_my){
mov_x = new_mx;
mov_y = new_my;
}
void move(const CBox& bounds, CPlayer* plys);
void draw(){
al_draw_filled_circle(box.x + box.w/2, box.y + box.h/2, box.w/2, color);
}
};
class GameLoop{
private:
CBox fieldbox(int, int, int, int);
/************************************************/
/***********ERROR HERE?? ERROR HERE??************/
/************************************************/
CBall ball(const CBox&, ALLEGRO_COLOR);
CPlayer player1(const CBox&, ALLEGRO_COLOR);
CPlayer player2(const CBox&, ALLEGRO_COLOR);
/*************************************************/
/*************************************************/
public:
GameLoop(Allegro&);
void GameStart(Allegro&);
void runTimerChecks(ALLEGRO_EVENT&, Allegro&);
void runExit(ALLEGRO_EVENT&, Allegro&, bool&);
void playerInput(ALLEGRO_EVENT&, bool&);
void endPlayerInput(ALLEGRO_EVENT&);
};
void CPlayer::move(CBox& bounds){
//make sure the player doesn't go off-bounds
testBounds(bounds);
box.y+=(int)mov_y;
//Players can't move horizontally, so no bounds checking in that matter
}
void CPlayer::testBounds(CBox& bounds){
if((mov_y < 0) && (box.y + mov_y < bounds.y)){
box.y = bounds.y;
mov_y = 0;
}
else if((mov_y > 0) && (box.y + box.h > bounds.y + bounds.h)){
box.y = bounds.y + bounds.h - box.h;
mov_y = 0;
}
}
//ghostbox is the precalculated ball's trajectory
void CBall::move(const CBox& bounds, CPlayer* plys){
CBox ghostbox(box.x+(int)mov_y, box.y+(int)mov_y, box.w, box.h);
// test collision for box players
testCollision(ghostbox, bounds, plys);
testBounds(ghostbox, bounds);
}
void CBall::testCollision(CBox& ghostbox, const CBox& bounds, CPlayer* plys){
for(int i = 0; i < 2; i++){
//a player cannot touch the ball twice in a row
if(i != last_touch){
CBox other = plys[i].getBox();
if(ghostbox.collides(other)){
//set the last touch to this player
last_touch = i;
//negate the "ghost movement" in x axis
ghostbox.x -= (int)mov_x;
//bounce horizontally
mov_x = -mov_x;
//bounce vertically to change the ball's trajectory
mov_y = (((box.y+box.h/2.0)-(other.y+other.h/2.0))/other.h)*10;
break;
}
}
}
}
int CBall::testBounds(CBox& ghostbox, const CBox& bounds){
if(ghostbox.y < bounds.y){
ghostbox.y = bounds.y;
mov_y = -mov_y;
}
else if(ghostbox.y + ghostbox.h > bounds.y + bounds.h){
ghostbox.y = (bounds.y + bounds.h - ghostbox.h);
mov_y = -mov_y;
}
if(ghostbox.x + ghostbox.w < bounds.x){
box.x = bounds.x + bounds.w/2 - bounds.w/2;
box.y = bounds.y + bounds.h/2 - bounds.h/2;
return 2;
}
else if(ghostbox.x > bounds.x + bounds.w){
box.x = bounds.x + bounds.w/2 - box.w/2;
box.y = bounds.y + bounds.h/2 - box.h/2;
return 1;
}
box = ghostbox;
return 0;
}
GameLoop::GameLoop(Allegro& alObject){
// This box is our playfield (covers the whole screen)
fieldbox(0,0,alObject.getWidth(), alObject.getHeight());
//we setup the ball at the center of the screen with a white color
ball(CBox(alObject.getWidth()/2-10,alObject.getHeight()/2-10,20,20),alObject.paint(255,255,255));
//red player on the left
player1(CBox(10,alObject.getHeight()/2-80/2,20,80), alObject.paint(255,0,0));
//blue player on the right
player2(CBox(alObject.getWidth()-10-20,alObject.getHeight()/2-80/2,20,80), alObject.paint(0,0,255));
}
void GameLoop::GameStart(Allegro& alObject){
/*
when this variable is set to true the program will quit the main loop
and free the allocated resources before quitting.
*/
bool exit = false;
//we tell the ball to move to the left
/***********************************************/
/***********************************************/
ball.setXYMovement(-5.0,5.0); // GENERATES THE ERROR
/***********************************************/
/***********************************************/
while(!exit){
al_wait_for_event(alObject.eventq, NULL);
while(al_get_next_event(alObject.eventq, &alObject.event)){
if(alObject.event.type == ALLEGRO_EVENT_TIMER){
runTimerChecks(alObject.event, alObject);
}
else if(alObject.event.type == ALLEGRO_EVENT_DISPLAY_CLOSE){
// quit if the user tries to close the window
runExit(alObject.event, alObject, exit);
}
else if(alObject.event.type == ALLEGRO_EVENT_KEY_DOWN){
playerInput(alObject.event, exit);
}
else if(alObject.event.type == ALLEGRO_EVENT_KEY_UP){
endPlayerInput(alObject.event);
}
}
}
}
void GameLoop::runTimerChecks(ALLEGRO_EVENT& event, Allegro& alObject){
if(alObject.event.timer.source == alObject.getTimer()){
//fill the screen with black
al_clear_to_color(alObject.paint(0,0,0));
//move and draw our two players
/**************************************************/
/**************************************************/
player1.move(fieldbox); // GENERATES THE ERROR
player1.draw(); // GENERATES THE ERROR
player2.move(fieldbox); // GENERATES THE ERROR
player2.draw(); // GENERATES THE ERROR
/**************************************************/
/**************************************************/
}
}
void GameLoop::runExit(ALLEGRO_EVENT& event, Allegro& alObject, bool& exit){
if(event.display.source == alObject.getDisplay()){
exit = true;
}
}
void GameLoop::playerInput(ALLEGRO_EVENT& event, bool& exit){}
void GameLoop::endPlayerInput(ALLEGRO_EVENT& event){}
Yes, the error is here:
CBall ball(const CBox&, ALLEGRO_COLOR);
CPlayer player1(const CBox&, ALLEGRO_COLOR);
CPlayer player2(const CBox&, ALLEGRO_COLOR);
This doesn't declare member variables called ball, player1 and player2, as you think it does (according to code like: player1.draw();). Instead, what you've written is a declaration of member functions with these names, taking in argument the parameters you've specified. Instead, you should do:
CBall ball;
CPlayer player1;
CPlayer player2;
Then in the constructor of GameLoop, initialize them with whatever value you want, using initialization lists:
GameLoop::GameLoop(Allegro& alObject) :
ball(/* ... */),
player1(/* ... */),
player2(/* ... */)
{
// ....
}