I'm working on Processing language for my assignment. It's an animation. The animation object(a ball) needs to go from top to bottom. I have declared variable as float x,y. Whenever I put if condition to increase size of it by 1 but it's not moving a single inch.
float x;
float y;
size(600, 400)
x = 0.4*width/8;
y = 0.4*height/8;
ellipse( width/2, x, 0.8*width/8, 0.8*width/8);
ellipse( y, height/2, 0.8*height/8, 0.8*height/8);
if(x < height){
x = x+1;
}
if(y < width){
y=y+1;
}
I am expecting the output as- the ball located on top moves towards down and stops at the bottom and the left ball moves to right and stops at the rightmost point.
You're using Processing in "static mode" which means your code runs once and then is done. Nothing happens after you reach the end of your code.
To take advantage of Processing's 60 FPS rendering loop, you need to specify setup() and draw() functions. Something like this:
float circleY;
void setup(){
size(200, 200);
circleY = height/2;
}
void draw(){
background(200);
ellipse(100, circleY, 20, 20);
circleY = circleY + 1;
}
Shameless self-promotion: here is a tutorial on animation in Processing.
Related
I'm having trouble with implementing gravity on objects.
I have a bunch of circle objects that I'm drawing using OpenGL. I'm using delta-x and delta-y to move the circles (balls). I'm trying to add a gravitational constant to the y coordinate each frame so it simulates being pulled downward, but I'm not sure exactly how to do that.
Here's the relevant code:
class Ball
{
public:
double x;
double y;
double radius;
double deltaX;
double deltaY;
};
std::vector<Ball> gAllBalls; // a vector of balls with random positions and delta-values
double gGravity = ?; // gravitational constant - I know it's 92 m/s^s, but I don't know how to apply that to deltaX and deltaY
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
for (auto &thisBall : gAllBalls)
{
// draw
glColor3d(thisBall.red, thisBall.green, thisBall.blue);
DrawCircle(thisBall.x, thisBall.y, thisBall.radius);
// gravity - not working
if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
{
thisBall.y += gGravity;
}
// wall bouncing
if (thisBall.y + thisBall.radius + thisBall.deltaY >= gScreenHeight) // up
{
thisBall.deltaY = -thisBall.deltaY;
}
if (thisBall.y + thisBall.deltaY - thisBall.radius < 0) // down
{
thisBall.deltaY = -thisBall.deltaY;
}
if (thisBall.x + thisBall.deltaX - thisBall.radius < 0) // left
{
thisBall.deltaX = -thisBall.deltaX;
}
if (thisBall.x + thisBall.radius + thisBall.deltaX >= gScreenWidth) // right
{
thisBall.deltaX = -thisBall.deltaX;
}
// move
thisBall.x += thisBall.deltaX;
thisBall.y += thisBall.deltaY;
}
glutSwapBuffers();
glutPostRedisplay();
}
A big problem I'm having is that I don't know how to calculate the gravity, since I'm using deltaX and deltaY instead of having separate speed and distance variables to calculate 92 m/s^2. However, no matter what I set the gravity to, the balls don't behave like they should - regardless of gravity strength, so there has to be something else wrong, but I don't know what.
I think the problem here is the physics, rather than the programming technique.
In your case, I would change the 'delta' members of your Ball class to 'speed', since they are a unit of distance that change the position of your object per cycle (time), however this is just a suggestion to make it easier to visualize...
class Ball
{
public:
double x;
double y;
double radius;
double speedX;
double speedY;
};
In second place, I in your code, you are changing the 'y' member, rather than the speed, and since gravity changes speed, hence the problem.
Try doing that, and for debugging purposes, I would try with punctual objects (no radius, just plain (x,y) coordinates).
So, to conclude, I would simply change your gravity code to the following:
// gravity - 'fixed'
if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
{
thisBall.speedY -= gGravity; //notice the '-'
}
The value of gravity should be absolute and positive, so as to keep things as simple as posible. If you try this, you should have an ideal simple physics simulator, with a ball of constant speedX (only changing its direction, not magnitude).
Please try this, and let me know how it went, good luck, keep it up =)
The snake in my game is basically a list of squares. Each square in this list is defined using GL_QUADS, which requires definition of two vertices (x,y and x1,y1) as so:
void Square::draw() const
{
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x1, y);
glVertex2f(x1, y1);
glVertex2f(x, y1);
glEnd();
}
The snake moves by insertion of a new element at the front of the list, and deletion of the last. So, if the snake was initially moving towards the left, and receives a command to move upwards, a square would be created above the snake's (previous) head, and the last square in the list will be removed.
To generate food, I have the following code:
void generate_food()
{
time_t seconds
time(&seconds);
srand((unsigned int)seconds);
x = (rand() % (max_width - min_width + 1)) + min_width;
y = (rand() % (max_height - min_height + 1)) + min_height;
x1 = foodx + 10;
y1 = foody + 10;
food = new Square{x,y,x1,y1 };
}
(Note: the width and height are dimensions of the playfield.)
I also implemented a function that grows the snake: if the coordinates of the snake's head match the coordinates of the food. However, when I run the program, the snake's head is never EXACTLY at the same coordinates as the food block... a few pixels off, here and there. Is there any way around this problem which does not require me to re-write all my code with a grid-based implementation?
As i understand your explanation when snake is moving you compare two squares: square of new head and food. So to get it work correctly you should detect collisions of squares and not full equality.
bool rectHitTest(const Square head, const Square food){
if ((head.x2 < food.x1 || head.y2 < food.y1) ||
(head.x1 > food.x2 || head.y1 > food.y2))
return false;
return true;
}
To allow it eat without graphical collision on the screen you can draw your food with base coords but test on collision with expanded for a few pixels
Here is my code:
void Draw()
{
int x = 59;
int y = 500;
int temp = x;
int colour;
for (int i = 0; i < 9; ++i)
{
for (int j = 0; j < 10; ++j)
{
if (i % 2 == 0)
colour = 2;
else
colour = 3;
DrawRectangle(x, y, 65, 25, colors[colour]);
x += 67;
}
x = temp;
y -= 39;
}
DrawRectangle(tempx, 0, 85, 12, colors[5]);
DrawCircle(templx, temply, 10, colors[7]);
}
// This function will be called automatically by this frequency: 1000.0 / FPS
void Animate()
{
templx +=5;
temply +=5;
/*if(templx>350)
templx-=300;
if(temply>350)
temply-=300;*/
glutPostRedisplay(); // Once again call the Draw member function
}
// This function is called whenever the arrow keys on the keyboard are pressed...
//
I am using OpenGL for this project. The function Draw() is used to print the bricks, slider, and the ball. The Animate() function is called automatically by the frequency given in the code. As it can be seen, I have incremented the values of templx and temply, but the ball goes out of screen as it crosses its limit. I have to deflect the ball if it collides with the paddle or the wall. What can I do to achieve this? All the conditions that I have used by now do not work properly.
So basically you would like to have a ball that is bouncing from the edges of your window. (For this answer I will ignore the slider, finding collision with the slider is very similar to finding collision with the walls).
templx and temply pair is position of your ball. I don't know what is the 3rd argument of DrawCircle function so I will assume that it is the radius. Let wwidth and wheight be width and height of a game window. Note that this magic constant 5 is, in fact, a velocity of the ball. Now ball is moving from upper left corner to lower right corner of your window. If you change 5 to -5 it will move from lower right corner to upper left corner.
Let's introduce two more variables vx and vy - velocity on x axis and velocity on y axis. The initial values will be 5 and 5. Now notice that when ball hits the right edge of the window it doesn't change its vertical velocity, it is still moving up/down but it changes its horizontal velocity from left->right to right->left. So if the vx was 5, after hitting the right edge of the window we should change it to -5.
The next problem is how to find out if we hit the edge of the window or not.
Note that the right-most point on the ball has the position templx + radius and the left-most point on the ball has the position templx - radius etc. Now to find out if we hit the wall or not we should just compare this values with window dimensions.
// check if we hit right or left edge
if (templx + radius >= wwidth || templx - radius <= 0) {
vx = -vx;
}
// check if we hit top or bottom edge
if (temply + radius >= wheight || temply - radius <= 0) {
vy = -vy;
}
// update position according to velocity
templx += vx;
temply += vy;
This is the source file where the function setLocation() is called (that includes for the graphics header file should have angle brackets, but it disappeared, so I used quotes)
#include "SFML/Graphics.hpp"
#include "ship.h"
const int WINDOW_WIDTH = 500;
const int WINDOW_HEIGHT = 500;
//==============================================================================
int main()
{
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)
Ship obj;
//ADD Code to set limits on ships location (call setMaxLocation);
//sets position of the ship in the middle of the screen
obj.setLocation(250, 250);
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
while (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
obj.rotateLeft();
//turn right with press of right button
while (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
obj.rotateRight();
//apply thrust with press of up button
while (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
obj.applyThrust();
//----------------------------------------------------------
//draw new frame
window.clear();
//draw ship
obj.updateLocation();
obj.draw(window);
//redisplay window
window.display();
}
return 0;
}
This is setLocation()'s definition, in the ship source file (same issue with the angle brackets, used quotes again).
#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;
//constructor
Ship::Ship(){
maxLocations.x = 500;
maxLocations.y = 500;
radius = 5;
location.x = 0;
location.y = 0;
velocity.x = 0;
velocity.y = 0;
angleDeg = 5;
}
void Ship::setLocation(double x, double y){
//Check and correct for the ship going out of bounds.
if (x < 0)
location.x = 0;
else if (x > maxLocations.x)
location.x -= maxLocations.x;
else
location.x = x;
if (y < 0)
location.y = 0;
else if (y > maxLocations.y)
location.y -= maxLocations.y;
else
location.y = y;
}
void Ship::updateLocation(){
location.x += velocity.x;
location.y -= velocity.y;
//Check and correct for the ship going out of bounds.
if (location.x < 0)
location.x = 0;
else if (location.x > maxLocations.x)
location.x -= maxLocations.x;
if (location.y < 0)
location.y = 0;
else if (location.y > maxLocations.y)
location.y -= maxLocations.y;
}
void Ship::draw(sf::RenderWindow& win) {
//Initializes the Ship class to an object
Ship obj;
// 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(obj.getLocation().x, obj.getLocation().y);
obj.setAngle(obj.getAngle());
win.draw(ship);
}
}
Finally this is the header file where the setLocation() prototype is located
#ifndef SHIP_H
#define SHIP_H
#include "vector.h"
class Ship {
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 of ship (for collision detection)
public:
//constructor
Ship();
//=============================================
//mutators
void setLocation(double x, double y);
void updateLocation();
void draw(sf::RenderWindow& win);
...
};
#endif
My issue is when I call setLocation() it doesn't change the location vector (as defined in the second source file) from (0, 0). When compiled the ship remains at (0, 0). What I want to happen is when I call setLocation(), the ship needs to change from (0, 0) to (250, 250), thus the ship on compiling starts in the middle of the screen, not a corner.
The problem at hand is you are not using the Ship object that you believe you are using. What I mean by that is you aren't drawing the ship object in your main function, instead you are creating a temporary ship object in your Ship::draw() method and then using that ships position to draw your shape. So the position will always be (0, 0) because your temp ship object get's initialized every frame with the position (0, 0) and then you use that temporary ship's position to draw your shape.
To make this more clear let's look at your code.
void Ship::draw(sf::RenderWindow& win) {
// This is a temporary object and is not the same as the one you defined in your
// main.cpp file. When this object is constructed it's location is (0, 0) by
// default.
Ship obj;
// 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));
// Here we are setting the shapes position to the position of the temporary
// Ship object that you defined above. Remember that it's default location is
// (0, 0) when constructed and you never changed it's location in the draw
// method.
ship.setPosition(obj.getLocation().x, obj.getLocation().y);
obj.setAngle(obj.getAngle());
win.draw(ship);
}
Now how do you fix this? That is easy. All you need to do is get rid of that temporary ship object in your draw method and instead use your location vector to set the position of the shape. Like this.
ship.setPosition(location.x, location.y);
It might be beneficial for your to study up on how objects and classes work in C++ before continuing on. It seems you might not understand exactly how they work and how different scopes of code work. But I will leave that for your to decide what to do.
Though I would like to point out a few other pointers for you.
1 - In your draw method you are updating the position of objects. This is generally a bad thing to do and you should avoid it. All updating code like when you change a objects position should happen in a update function/method. The drawing methods of entities should only have drawing code in them. The reason for this is because usually drawing and updating happen at different time steps in the main game loop.
2 - Your updateLocation method won't work like you think it will. The reason is because you are doing location.y -= velocity.y; when in reality you should be adding the velocity of y to location just like you did with x.
3 - I would advise against using sfml's setFrameRateLimit() method and instead use your own timestep which will be much more accurate (SFML's version uses sf::Sleep which is notorious for being inaccurate) and give you much more control over your time step. If you don't know about time steps I would highly suggest reading this great article on it. It will save you hours of headaches. http://gafferongames.com/game-physics/fix-your-timestep/
4 - Let's take a look at this line.
else if (x > maxLocations.x)
location.x -= maxLocations.x;
Now let's say that maxLocations.x = 500 like in your example and let's also say that location.x = 550. Do you really want the location to be x = 50? Wouldn't a more logical step be to set x to x = maxLocations.x? Not sure if this is what you wanted but thought I would point it out.
Hopefully this will help you a bit and I would always be glad to answer any other questions you might have. Wish you the best of luck with your project.
I'm using glut for a game right now and I'm trying to keep the mouse inside the window. This isn't a first person shooter so locking it in the center is no good. I already know about glutWarpPointer(int, int); and I've trying things that work (kinda).
I've tried having the mouse warp back to the nearest edge of the window when it leaves, this works, but for a split second you see the mouse outside of the window and teleport back in. I don't want that, I want it to seem like the mouse just hits the edge of the window and stops going any further in that direction, while keeping movement in any other available direction. Like you would expect it to work.
This is not exactly an answer to your question, but it is an answer to your problem!
Almost every game has its own cursors. They would hide the mouse, and draw the cursor manually where the mouse should be positioned.
If you get your own cursor image and do as I said, you can simply draw the curser at the edge of the screen, even though the mouse position reads out of boundaries. Then you can warp the mouse back in.
Tried to search and figure this out and couldn't find an answer, so I implemented it myself. Here is what worked for my first person camera case:
callback from glutPassiveMotion
CODE SAMPLE
void Game::passiveMouseMotion(int x, int y)
{
//of my code for doing the cam, yours is may be different, this is based on the example from https://learnopengl.com/Getting-started/Camera
if (firstMouse) {
lastX = x;
lastY = y;
firstMouse = false;
}
float xoffset = x - lastX;
float yoffset = lastY - y; // reversed since y-coordinates go from bottom to top
lastX = x;
lastY = y;
camera->ProcessMouseMovement(xoffset, yoffset);
glutPostRedisplay();
//this is the main thing that keeps it from leaving the screen
if ( x < 100 || x > win_w - 100 ) { //you can use values other than 100 for the screen edges if you like, kind of seems to depend on your mouse sensitivity for what ends up working best
lastX = win_w/2; //centers the last known position, this way there isn't an odd jump with your cam as it resets
lastY = win_h/2;
glutWarpPointer(win_w/2, win_h/2); //centers the cursor
} else if (y < 100 || y > win_h - 100) {
lastX = win_w/2;
lastY = win_h/2;
glutWarpPointer(win_w/2, win_h/2);
}
}
Hope this helps!