sfml ship not wrapping at the window end - c++

Well friends, I have returned here to try and get a little help once again. The issue is this, the ship on build doesn't wrap. That is to say it doesn't reappear on the other side of the window when it goes past the windows limit. The function called setmaxLocations() is being very strange. It erases the ship, or doesn't set the max location. So here is my code. Bear with me, this is a large project. If I messed up the format just let me know, I check often so it'll get fixed close to when you tell me.
main implementation cpp:
#include <SFML/Graphics.hpp>
#include "ship.h"
const int WINDOW_WIDTH = 700;
const int WINDOW_HEIGHT = 700;
//==============================================================================
int main()
{
Ship ship;
sf::RenderWindow window( sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT),
"Delta Quadrant", sf::Style::Titlebar | sf::Style::Close);
window.setFramerateLimit(120);
// this causes loop to execute 120 times a second at most.
// (a delay is automatically added after screen is drawn)
//set's the limit on the ship's location to the window dimensions;
ship.setmaxLocations(WINDOW_WIDTH, WINDOW_HEIGHT);
//sets position of the ship in the middle of the screen
ship.setLocation(WINDOW_WIDTH/2, WINDOW_HEIGHT/2);
while (window.isOpen())
{
//----------------------------------------------------------
//handle user input (events and keyboard keys being pressed)
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
//turn left with press of left button
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
ship.rotateLeft();
//turn right with press of right button
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
ship.rotateRight();
//apply thrust with press of up button
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
ship.applyThrust();
//----------------------------------------------------------
//draw new frame
window.clear();
//draw ship
ship.updateLocation();
ship.draw(window);
//redisplay window
window.display();
}
return 0;
}
SpaceObject header:
#ifndef SPACE_OBJECT_H
#define SPACE_OBJECT_H
#include "vector.h"
class SpaceObject {
private:
Vector maxLocations; //maximum allowable values for location
Vector location; //current location (x,y)
Vector velocity; //current velocity (in pixels/frame)
double angleDeg; //angle ship is facing, in degrees
double radius; //gross radius (for collision detection)
public:
SpaceObject();
//--------------------------------------------
//mutators
void setLocation(double x, double y);
void setVelocity(double velocityX, double velocityY);
void setAngle(double angDeg);
void setRadius(double radius);
//--------------------------------------------
//accessors
Vector getLocation();
Vector getVelocity();
double getAngle();
double getRadius();
//--------------------------------------------
//others
void updateLocation();
void setmaxLocations(double x, double y);
};
#endif
SpaceObject source file:
#include<cmath>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include"vector.h"
#include "SpaceObject.h"
//constructor
SpaceObject::SpaceObject() {
maxLocations.x = 500;
maxLocations.y = 500;
radius = 5;
location.x = 0;
location.y = 0;
velocity.x = 0;
velocity.y = 0;
angleDeg = 0;
}
//================================================================
//mutators
//================================================================
// Function: setLocation
//
// Description: Sets the x and y values of the SpaceObject's location
// Argument list:
// x(I) - x coordinate for SpaceObject's location
// y(I) - y coordinate for SpaceObject's location
//=================================================================*/
void SpaceObject::setLocation(double x, double y){
//Check and correct for the SpaceObject going out of bounds.
if (x < 0)
location.x += maxLocations.x;
else if (x > maxLocations.x)
location.x -= maxLocations.x;
else
location.x = x;
if (y < 0)
location.y += maxLocations.y;
else if (y > maxLocations.y)
location.y -= maxLocations.y;
else
location.y = y;
}
//================================================================
// Function: setVelocity
//
// Description: Sets the velocity for the x and y direction of the SpaceObject
// Argument list:
// velocityX(I) - sets the velocity in the x direction
// velocityY(I) - sets the velocity in the y direction
//=================================================================
void SpaceObject::setVelocity(double velocityX, double velocityY){
velocity.x = velocityX;
velocity.y = velocityY;
}
//================================================================
// Function: setLocation
//
// Description: Sets the directional angle of the SpaceObject
// Argument List:
// angDeg(I) - sets the SpaceObjects angle
//=================================================================*/
void SpaceObject::setAngle(double angDeg){
while (angDeg >= 360)
angDeg -= 360;
while (angDeg < 0)
angDeg += 360;
angleDeg = angDeg;
}
//================================================================
//accessors
//================================================================
// Function: getRadius
// Description: Returns the Radius
//
// Return value:
// Radius - the SpaceObjects turning axis
//=================================================================*/
double SpaceObject::getRadius(){
return radius;
}
//================================================================
// Function: getLocation
// Description: Returns the x and y values of the SpaceObjects location
//
// Return value:
// location - the location of the SpaceObject
//=================================================================*/
Vector SpaceObject::getLocation(){
return location;
}
//================================================================
// Function: getVelocity
// Description: Returns the x and y values of the SpaceObjects directional velocity
//
// Return value:
// Velocity
//=================================================================*/
Vector SpaceObject::getVelocity(){
return velocity;
}
//================================================================
// Function: getAngle
// Description: returns the angle
//
// Return value:
// Angle - the SpaceObjects direction
//=================================================================*/
double SpaceObject::getAngle(){
return angleDeg;
}
//============================================
//other functions
//================================================================
// Function: setmaxLocations
//
// Description: Sets the x and y values of the SpaceObject's max possible area of movement
// Argument list:
// x(I) - max width of SpaceObject's possible positions
// y(I) - max heigth of SpaceObject's possible positions
//=================================================================*/
void SpaceObject::setmaxLocations(double x, double y){
maxLocations.x = x;
maxLocations.y = y;
}
//================================================================
// Function: updateLocations
//
// Description: Sets the x and y values of the SpaceObject's location while including the change with velocity
//=================================================================*/
void SpaceObject::updateLocation(){
location.x = location.x + velocity.x;
location.y = location.y + velocity.y;
}
ship header file:
#ifndef SHIP_H
#define SHIP_H
#include "SpaceObject.h"
class Ship: public SpaceObject {
public:
Ship();
void rotateLeft();
void rotateRight();
void applyThrust();
void draw(sf::RenderWindow& win);
};
#endif
ship source file:
#include<cmath>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include"vector.h"
#include "ship.h"
//Constants
const double PI = 3.14159;
const double THRUST = 0.005;
const double TURN_SPEED = 1;
Ship::Ship() {
}
//============================================
//other functions
//================================================================
// Function: rotateLeft
//
// Description: turns the ship left by subtracting from the ship's angle
//=================================================================*/
void Ship::rotateLeft(){
int newAngle;
newAngle = getAngle() - TURN_SPEED;
setAngle(newAngle);
}
//================================================================
// Function: rotateRight
//
// Description: turns the ship Right by adding to the ship's angle
//=================================================================*/
void Ship::rotateRight(){
int newAngle;
newAngle = getAngle() + TURN_SPEED;
setAngle(newAngle);
}
//================================================================
// Function: applyThrust
//
// Description: Sets the x and y value of the ship's movement
//=================================================================*/
void Ship::applyThrust(){
double forcex = cos((getAngle()-90)*PI/180) * .005;
double forcey = sin((getAngle()-90)*PI/180) * .005;
setVelocity(getVelocity().x + forcex, getVelocity().y + forcey);
}
//--------------------------------------------------------------------------
// Function: draw
// Description: draws the ship on the given window
// Parameters:
// win - the window for drawing the ship
//--------------------------------------------------------------------------
void Ship::draw(sf::RenderWindow& win) {
// draw ship
sf::ConvexShape ship;
ship.setPointCount(3);
ship.setPoint(0, sf::Vector2f(10, 0));
ship.setPoint(1, sf::Vector2f(0, 25));
ship.setPoint(2, sf::Vector2f(20, 25));
sf::Vector2f midpoint(10,15);
ship.setOrigin(midpoint);
ship.setFillColor(sf::Color(0, 0, 0));
ship.setOutlineThickness(1);
ship.setOutlineColor(sf::Color(255, 255, 255));
ship.setPosition(getLocation().x, getLocation().y);
ship.setRotation(getAngle());
win.draw(ship);
}
vector header file (just for clarity):
#ifndef VECTOR_H
#define VECTOR_H
struct Vector{
float x;
float y;
};
#endif

It seems that SpaceObject::setLocation() does the actual checking to see if the ship is in bounds, yet this function is only called once at the beginning of your main(). It needs to be called within the loop so it can continually check that the ship has a valid location. I would recommend calling it within SpaceObject::updateLocation()

Related

How to fix spaceship interaction with the boundaries and more?

#pragma once
#include "Globals.h"
#include "ResourceManager.h"
#include "ResourceIdentifier.h"
#include "Entity.h"
#include <iostream>
#include <cmath>
class Shooter : public Entity{
private:
bool m_isClicked;
bool m_ableToMove;
float m_lastAngle;
bool m_mouseInBounds;
sf::Vector2i m_targetPos;
public:
Shooter();
void initialize(const TextureManager&);
void moveShip(float dt);
void angleShipToMouse(const sf::Vector2i&);
void handleInput(const sf::Event&, const sf::Vector2i&);
void update(const sf::Vector2i&, float);
void adjustingTarget();
};
#include "SpaceShooter.h"
Shooter::Shooter() : m_ableToMove(false), m_isClicked(false), m_lastAngle(0)
{
}
void Shooter::initialize(const TextureManager& text)
{
m_speed = sf::Vector2i(500, 500);
this->m_sprite.setTexture(text.get(TextureID::Shooter));
this->m_sprite.setOrigin(m_sprite.getGlobalBounds().width / 2.0f, m_sprite.getGlobalBounds().height / 2.0f);
this->m_sprite.setPosition(Globals::_windowWidth / 2.0f, Globals::_windowHeight / 2.0f); //start 50 units out
}
void Shooter::moveShip(float dt) {
if (m_isClicked && !m_ableToMove) {
m_ableToMove = true;
m_isClicked = false;
}
if (m_ableToMove) {
adjustingTarget();
sf::Vector2f shipComponentDistances(abs(m_targetPos.x - getX()), abs(m_targetPos.y - getY()));
sf::Vector2f shipVelocity(cos(m_angle * Globals::deg2rad) * dt * m_speed.x,
sin(m_angle*Globals::deg2rad) * dt * m_speed.y);
float targetDistance = sqrt(pow(shipComponentDistances.x, 2) + pow(shipComponentDistances.y, 2));
float distanceToTravel = sqrt(pow(shipVelocity.x, 2) + pow(shipVelocity.y, 2));
if (targetDistance > distanceToTravel) {
this->m_sprite.move(shipVelocity);
m_lastAngle = m_angle;
// std::cout << distance << std::endl;
}
else {
this->m_sprite.setPosition(m_targetPos.x - 0.01, m_targetPos.y - 0.01);
std::cout << m_lastAngle << std::endl;
this->m_sprite.setRotation(m_lastAngle);
std::cout << this->m_sprite.getRotation() << std::endl;
m_ableToMove = false;
m_isClicked = false;
}
}
}
void Shooter::angleShipToMouse(const sf::Vector2i& mousePosition) {
//position of mouse relative to ship in 0 rotation reference frame(absolute)
sf::Vector2f mouseRelativeShip(mousePosition.x - getX(), mousePosition.y - getY());
float rotation = atan2(mouseRelativeShip.y, mouseRelativeShip.x)*Globals::rad2deg; //atan2 produces negative angles if vector is in QUADS 1&2, positive in QUADS 3&4
this->m_sprite.setRotation(rotation);
m_angle = this->m_sprite.getRotation();
}
void Shooter::handleInput(const sf::Event& event, const sf::Vector2i& mousePos) {
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {
if (!m_ableToMove && !m_isClicked) {
m_isClicked = true;
m_targetPos = mousePos;
}
}
}
void Shooter::update(const sf::Vector2i& mousePosition, float dt) {
angleShipToMouse(mousePosition);
moveShip(dt);
}
void Shooter::adjustingTarget()
{
if (m_targetPos.x < spriteWidth() / 2.0f) {
m_targetPos.x = spriteWidth() / 2.0f;
}
else if (m_targetPos.x > Globals::_windowWidth - spriteWidth() / 2.0f) {
m_targetPos.x = Globals::_windowWidth - spriteWidth() / 2.0f;
}
else if(m_targetPos.y < spriteHeight() / 2.0f){
m_targetPos.y = spriteHeight() / 2.0f;
}
else if (m_targetPos.y > Globals::_windowHeight - spriteHeight() / 2.0f) {
m_targetPos.y = Globals::_windowHeight - spriteHeight() / 2.0f;
}
}
The problems with my spaceship are:
1. despite not allowing for changing of targetPos when !moving, clicking while its moving to a different location will cause it to redirect the ship. Holding down the ship causes it to follow the mouse cursor.
once ship reaches the targetPosition, the rotation of the ship gets set to 0, im trying to make it retain the rotation of the angle just prior to it reaching its destination (e.g. distance to targetPos is 0).
When it reaches the boundaries sometimes it can go through it despite me adjusting the targetPosition if the mouse is too far into a deadzone the ship cannot enter.

C++ & SFML Separating Axis Theorem

I'm trying to implement collision detection in sfml using the separating axis theorem but my function to get the min translation vector (getMtv()) is always returning that there is a collision (MTV::IsValid()). I was following a tutorial here
but I can't see where I went wrong.
#include <iostream>
#include <math.h>
#include <SFML/Graphics.hpp>
#include <gtest/gtest.h>
typedef sf::Vector2f Vector2;
typedef sf::Vector2f Axis;
typedef sf::Vector2f Projection;
typedef std::vector<Axis> AxesVec;
class MTV
{
private:
bool _valid;
Axis _axis;
float _overlap;
public:
MTV(Axis axis, float overlap, bool valid)
{
_valid = valid;
_overlap = overlap;
_axis = axis;
}
bool IsValid() const
{
return _valid;
}
};
Vector2 perpendicular(Vector2 v)
{
return Vector2(v.y, -v.x);
}
float dot(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.x) + (vec1.y * vec2.y);
}
float magnitude(Vector2 v)
{
return std::sqrt(dot(v,v));
}
class Polygon : public sf::ConvexShape
{
public:
const AxesVec& GetAxes() const
{
return axes;
}
AxesVec axes;
void generateAxes()
{
for (int i = 0; i < getPointCount(); i++)
{
// get the current vertex
Vector2 p1 = getPoint(i); //shape.vertices[i];
// get the next vertex
Vector2 p2 = getPoint(i + 1 == getPointCount() ? 0 : i + 1);
// subtract the two to get the edge vector
Vector2 edge = p1 - p2;
// get either perpendicular vector
Vector2 normal = perpendicular(edge);
// the perp method is just (x, y) => (-y, x) or (y, -x)
axes.push_back(normal / magnitude(normal));
}
};
float cross(Vector2 vec1, Vector2 vec2)
{
return (vec1.x * vec2.y) - (vec1.y * vec2.x);
}
Vector2 project(Polygon p, Axis axis)
{
float min = dot(axis, p.getPoint(0)); //axis.dot(shape.vertices[0]);
float max = min;
for (int i = 1; i < p.getPointCount(); i++)
{
// NOTE: the axis must be normalized to get accurate projections
float prj = dot(axis, p.getPoint(i));//axis.dot(shape.vertices[i]);
if (prj < min)
{
min = prj;
}
else if (prj > max)
{
max = prj;
}
}
//Projection proj = new Projection(min, max);
return Projection(min, max);
}
class Collison
{
private:
Vector2 mtv;
Polygon a;
Polygon b;
};
bool overlap(Projection a, Projection b)
{
// x = min & y = max
return !(a.x > b.y || a.x > b.y);
}
float getOverlap(Projection a, Projection b)
{
// x = min & y = max
return (a.y < b.y) ? a.y - b.x : b.y - a.x;
}
MTV getMtv(Polygon a, Polygon b)
{
float overlapMax = std::numeric_limits<float>::infinity();// really large value;
float Overlap;
Axis smallest;// = null;
AxesVec axesA = a.GetAxes();
AxesVec axesB = b.GetAxes();
// loop over the axes1
for (auto&& axis : axesA) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
float o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
for (auto&& axis : axesB) //for (int i = 0; i < axes1.length; i++)
{
//Axis axis = axes1[i];
// project both shapes onto the axis
Projection pA = project(a, axis);
Projection pB = project(b, axis);
// do the projections overlap?
if (!overlap(pA, pB)) //(!p1.overlap(p2))
{
// then we can guarantee that the shapes do not overlap
return MTV(smallest, 0, false);
}
else
{
// get the overlap
double o = getOverlap(pA, pB); //p1.getOverlap(p2);
// check for minimum
if (o < overlapMax)
{
// then set this one as the smallest
Overlap = o;
smallest = axis;
}
}
}
//MTV mtv = new MTV(smallest, overlap);
// if we get here then we know that every axis had overlap on it
// so we can guarantee an intersection
return MTV(smallest, Overlap, true);
}
int main(int argc, char **argv)
{
Polygon polygon;
polygon.setPointCount(3);
polygon.setPoint(0, sf::Vector2f(500, 100));
polygon.setPoint(1, sf::Vector2f(250, 500));
polygon.setPoint(2, sf::Vector2f(750, 500));
polygon.setFillColor(sf::Color::Red);
polygon.generateAxes();
Polygon polygon2;
polygon2.setPointCount(3);
polygon2.setPoint(0, sf::Vector2f(100, 0));
polygon2.setPoint(1, sf::Vector2f(50, 150));
polygon2.setPoint(2, sf::Vector2f(150, 150));
polygon2.generateAxes();
//polygon2.setPoint(0, sf::Vector2f(100, 0));
//polygon2.setPoint(1, sf::Vector2f(500, 150));
//polygon2.setPoint(2, sf::Vector2f(250, 150));
polygon2.setFillColor(sf::Color::Green);
sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
// clear the window with black color
window.clear(sf::Color::Black);
// draw everything here...
window.draw(polygon);
window.draw(polygon2);
std::cout << getMtv(polygon, polygon2).IsValid() << std::endl;
// end the current frame
window.display();
}
return 0;
}

Polymorphism & Derived Classes

So here is my code:
//Shapes.cpp
#include <cassert>
#include <cmath>
#include "shapes.h"
using namespace std;
const double PI = 3.14159;
////////////////////////// Ellipse //////////////////////////
Ellipse::Ellipse() : xRad(0), yRad(0){}
Ellipse::Ellipse(double xRad_in, double yRad_in)
: xRad(xRad_in), yRad(yRad_in) {}
double Ellipse::area() const {
return PI * xRad * yRad;
}
void Ellipse::draw(Canvas *canvas) const{
// Iterate through the grid of (x,y) pixel coordinates
// in the canvas.
for(int x = 0; x < CANVAS_WIDTH; ++x){
for(int y = 0; y < CANVAS_HEIGHT; ++y){
// The ellipse contains the point (x,y) if and only if
// ((x-xPos)/xRad)^2 + ((y-yPos)/yRad)^2 <= 1
double xDiff = x - get_xPos();
double yDiff = y - get_yPos();
if( (xDiff/xRad)*(xDiff/xRad) + (yDiff/yRad)*(yDiff/yRad) <= 1 ){
// If the pixel is contained in the ellipse, set it to true
canvas->setPixel(x, y, true);
}
}
}
}
///////////////////////// End Ellipse /////////////////////////
////////////////////////// Circle //////////////////////////
// PUT YOUR CODE (IMPLEMENTATIONS) FOR CIRCLE HERE
Circle::Circle(double rad_in)
: Ellipse(rad_in, rad_in) {}
//Use Ellipse's area function by sending it the radius of the
//circle for the xRad and yRad parameters
//Use Ellipse's draw function
///////////////////////// End Circle /////////////////////////
//////////////////////// Rectangle /////////////////////////
// PUT YOUR CODE (IMPLEMENTATIONS) FOR RECTANGLE HERE
Rectangle::Rectangle(double w_in, double h_in)
: w(w_in), h(h_in) {}
double Rectangle::area() const {
return w * h;
}
void Rectangle::draw(Canvas *canvas) const{
// Iterate through the grid of (x,y) pixel coordinates
// in the canvas.
for(int x = 0; x < CANVAS_WIDTH; ++x){
for(int y = 0; y < CANVAS_HEIGHT; ++y){
// The Rectangle contains the point (x,y) if and only if
// ((x-xPos)/xRad)^2 + ((y-yPos)/yRad)^2 <= 1
double xDiff = x - get_xPos();
double yDiff = y - get_yPos();
if( abs(xDiff) <= w/2 && abs(yDiff) <= h/2 ){
// If the pixel is contained in the Rectangle, set it to true
canvas->setPixel(x, y, true);
}
}
}
}
//////////////////////// End Rectangle //////////////////////
Along with the corresponding .h file:
// Shapes.h
#ifndef SHAPES_H
#define SHAPES_H
#include "Canvas.h"
/////////////////////////// Shape ///////////////////////////
class Shape {
public:
//EFFECTS: creates a shape with initial position (0,0)
Shape() : xPos(0), yPos(0) {}
//EFFECTS: returns the area of this Shape
virtual double area() const = 0;
//MODIFIES: canvas
//EFFECTS: draws this shape onto canvas at its current position
virtual void draw(Canvas *canvas) const {}
//MODIFIES: xPos, yPos
//EFFECTS: sets the position of this shape
void setPosition(double xPos_in, double yPos_in){
xPos = xPos_in;
yPos = yPos_in;
}
double get_xPos() const { return xPos; }
double get_yPos() const { return yPos; }
private:
double xPos; // The x position of this shape
double yPos; // The y position of this shape
};
///////////////////////// End Shape /////////////////////////
////////////////////////// Ellipse //////////////////////////
class Ellipse : public Shape{
public:
Ellipse();
//REQUIRES: xRad_in, yRad_in are non-negative
//EFFECTS: creates an Ellipse with given x and y radii
Ellipse(double xRad_in, double yRad_in);
//EFFECTS: returns the area of this Ellipse
virtual double area() const;
//MODIFIES: canvas
//EFFECTS: draws this shape onto canvas
virtual void draw(Canvas *canvas) const;
private:
double xRad; //Half the x-axis of the ellipse
double yRad; //Half the y-axis of the ellipse
};
///////////////////////// End Ellipse ////////////////////////
///////////////////////////////////////////////////////////////
// DO NOT MODIFY ABOVE THIS LINE //
///////////////////////////////////////////////////////////////
////////////////////////// Circle //////////////////////////
// PUT YOUR CODE (DECLARATION) FOR CIRCLE HERE
class Circle : public Ellipse{
public:
//REQUIRES: rad_in is non-negative
//EFFECTS: creates an Circle with given radius
Circle(double rad_in);
//EFFECTS: returns the area of this Circle
virtual double area() const;
//MODIFIES: canvas
//EFFECTS: draws this shape onto canvas
virtual void draw(Canvas *canvas) const;
private:
double xRad; //Radius of the Circle
double yRad; //Radius of the Circle
};
///////////////////////// End Circle /////////////////////////
//////////////////////// Rectangle /////////////////////////
// PUT YOUR CODE (DECLARATION) FOR RECTANGLE HERE
class Rectangle : public Shape{
public:
//REQUIRES: xRad_in, yRad_in are non-negative
//EFFECTS: creates an Rectangle with given x and y radii
Rectangle(double w_in, double h_in);
//EFFECTS: returns the area of this Rectangle
virtual double area() const;
//MODIFIES: canvas
//EFFECTS: draws this shape onto canvas
virtual void draw(Canvas *canvas) const;
private:
double w; //Length of the Rectangle
double h; //Width of the Rectangle
};
//////////////////////// End Rectangle //////////////////////
#endif /* SHAPES_H */
I am supposed to be making Rectangle derived from Shape and Circle derived from Ellipse, both with the corresponding functions that are present in their implementations, and I thought my code had done so, but I got the following compiler error:
shapes.cpp: In constructor \u2018Circle::Circle(double)\u2019:
shapes.cpp:47:30: error: no matching function for call to \u2018Ellipse::Ellipse()\u2019
: xRad(rad_in), yRad(rad_in) {}
^
shapes.cpp:47:30: note: candidates are:
shapes.cpp:12:1: note: Ellipse::Ellipse(double, double)
Ellipse::Ellipse(double xRad_in, double yRad_in)
^
shapes.cpp:12:1: note: candidate expects 2 arguments, 0 provided
In file included from shapes.cpp:4:0:
shapes.h:45:7: note: Ellipse::Ellipse(const Ellipse&)
class Ellipse : public Shape{
^
shapes.h:45:7: note: candidate expects 1 argument, 0 provided
I really have no idea what's wrong. Please help!
EDIT: Additional Code necessary for compile:
// Canvas.cpp
#include <iostream>
#include <cassert>
#include "Canvas.h"
using namespace std;
///////////////////////// Canvas ///////////////////////////
Canvas::Canvas(){
for(int row = 0; row < CANVAS_HEIGHT; ++row){
for(int col = 0; col < CANVAS_WIDTH; ++col){
grid[row][col] = false;
}
}
}
void Canvas::setPixel(int x, int y, bool value){
assert(0 <= x); assert(x < CANVAS_WIDTH);
assert(0 <= y); assert(y < CANVAS_HEIGHT);
grid[y][x] = value;
}
void Canvas::print() const {
for(int row = 0; row < CANVAS_HEIGHT; ++row){
for(int col = 0; col < CANVAS_WIDTH; ++col){
cout << (grid[CANVAS_HEIGHT-row-1][col] ? PIXEL_ON : PIXEL_OFF) << " ";
}
cout << endl;
}
}
////////////////////////// End Canvas /////////////////////////
And Canvas.h:
#ifndef CANVAS_H
#define CANVAS_H
///////////////////////// Canvas ///////////////////////////
//Canvas Constants
const int CANVAS_WIDTH = 30;
const int CANVAS_HEIGHT = 30;
const char PIXEL_ON = '#';
const char PIXEL_OFF = ' ';
class Canvas {
//OVERVIEW: A Canvas object represents a 2D grid of "pixels"
// which can be set to either "on" or "off". A Canvas
// knows how to print itself out to the terminal. The
// canvas has a fixed width and height and the origin
// (0,0) of the canvas's coordinate system is at the
// bottom left.
public:
//EFFECTS: creates a new Canvas with size CANVAS_WIDTH x CANVAS_HEIGHT
Canvas();
//REQUIRES: the pixel is on the canvas (0 <= x < CANVAS_WIDTH, 0 <= y < CANVAS_HEIGHT)
//MODIFIES: grid
//EFFECTS: if value is true, turns the pixel at (x,y) on
// if value is false, turns the pixel at (x,y) off
void setPixel(int x, int y, bool value);
//EFFECTS: prints this canvas to cout
void print() const;
private:
bool grid[CANVAS_HEIGHT][CANVAS_WIDTH];
};
////////////////////////// End Canvas /////////////////////////
#endif /* CANVAS_H */
Circle inherits from Ellipse, but Ellipse does not have a default constructor. Therefore either provide one, or call the desired constructor of Ellipse in the initialization list of Circle's constructor.

class declaration error: insufficient contextual information to determine type

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(/* ... */)
{
// ....
}

C++ Sprite class with Vector Object as Member

Ok, I'm having this problem with my Sprite class. Basically the sprite class should have a object of class Vector as its member with Vector being a class with both angle and speed. The Vector class has a Vector(double,double) constructor so the speed and angle can be set at its initialization but when I make my sprite class. It sends an error that its calling Vector(), a blank constructor, and that it doesn't exist. I'm trying to figure out why its calling Vector(). Here is my code from both the Sprite and Vector classes.
#Vector.h
#ifndef VECTOR_H
#define VECTOR_H
class Vector
{
public:
Vector(double,double);
double getX();
double getY();
double getSpeed();
double getAngle();
void setSpeed(double);
void setAngle(double);
private:
double speed,angle;
};
#endif
#Vector.h
#include "SDL/SDL.h"
#include "vector.h"
#include "math.h"
Vector::Vector(double speed,double angle)
{
this -> speed = speed;
this -> angle = angle;
}
double Vector::getX()
{
return speed*cos(angle);
}
double Vector::getY()
{
return speed*sin(angle);
}
double Vector::getSpeed()
{
return speed;
}
double Vector::getAngle()
{
return angle;
}
void Vector::setAngle(double angle)
{
this -> angle = angle;
}
void Vector::setSpeed(double speed)
{
this -> speed = speed;
}
#Sprite.h:
#ifndef SPRITE_H
#define SPRITE_H
#include "vector.h"
class Sprite
{
public:
Sprite(int x,int y);
SDL_Rect getRect();
SDL_Surface* getImage();
void setRect(SDL_Rect);
void move();
void draw(SDL_Surface*);
private:
Vector movement;
double x,y,lastX,lastY,angle,speed;
SDL_Rect rect;
SDL_Surface* image;
};
#endif
#Sprite.cpp:
#include "SDL/SDL.h"
#include "sprite.h"
#include "functions.h"
#include <cmath>
Sprite::Sprite(int x, int y)
{
this -> x = x;
this -> y = y;
lastX = x;
lastY = y;
image = loadImage("box.png");
rect.x = x;
rect.y = y;
rect.w = image->w;
rect.h = image->h;
speed = 1;
angle = 0;
}
SDL_Rect Sprite::getRect()
{
return rect;
}
SDL_Surface* Sprite::getImage()
{
return image;
}
void Sprite::setRect(SDL_Rect rect)
{
this -> rect = rect;
}
void Sprite::move()
{
lastX = x;
lastY = y;
x += speed*cos(angle);
y += speed*sin(angle);
rect.x = int(x);
rect.y = int(y);
}
void Sprite::draw(SDL_Surface* dest)
{
blit(image,dest,int(x),int(y));
}
Your Sprite class has a Vector member that will be constructed when the Sprite is constructed. At the moment, the Vector will be initialized with the default constructor because you haven't specified otherwise. If you want a specific constructor of Vector to be used, you need to add an initialization list to the constructor of Sprite:
Sprite::Sprite(int x, int y)
: movement(1.0, 0.0)
{
// ...
}
This will initialise movement with arguments 1 and 0. In fact, you might as well add other members to your initialization list too:
Sprite::Sprite(int x, int y)
: movement(1.0, 0.0), x(x), y(y), lastX(x), lastY(y) // and so on...
{
// ...
}
The Vector is created in Sprite::Sprite(int x, int y). The blank constructor for Vector is called because you do not call a constructor in the initializer list: in fact, you leave the Vector movement completely uninitialized!
Do this:
Sprite::Sprite(int x, int y):
movement(3.14, 2.7)
{
...
}
to construct movement using a two argument constructor. I would pick better values than 3.14 and 2.7, those are just sample values.
I would also consider creating a public no-argument constructor on Vector for ease of use that initalizes speed and angle to zero.