I was reading this topic and I decided to give it a shot. To my astonishment it really seemed easier than what I am making it I guess. I have some confusion about the "DesiredPos" variable. Well at least in my implementation. I am trying to move a window around constantly and have it react like a ball when it hits the monitors edges. Like the ball in the game Pong. I have made programs like this that move the mouse, But I can't seem to get my head around this one.
This is what I have so far, I have limited experience when it comes to a lot of functions in the Windows API. Keep in mind this is a hardcore rough draft.
EDIT
I haven't implemented any of the collision detection yet I just wanted to get the moving portion working.
#include <windows.h>
#include <math.h>
int newX(int oldx);
int newY(int oldy);
double SmoothMoveELX(double x);
int main()
{
int lengthInMs = 10*1000;
HWND notepad = FindWindow("Notepad",NULL);
RECT window;
SetTimer(
notepad,
NULL,
30,
(TIMERPROC)NULL
);
int startTime = GetTickCount();
int pos = elap / lengthInMs;
while(1)
{
RECT window;
GetWindowRect(notepad,&window);
int elap = (GetTickCount() - startTime);
if(elap >= lengthInMs)
{
int NEWX = NewX(window.x);
int NEWY = NewY(window.y);
MoveWindow(
notepad,
NEWX,
NEWY,
100,
100,
TRUE
);
}
}
}
int NewX(int oldx)
{
int newx = oldx*(1-SmoothMoveELX(pos))
+ 10 *SmoothMoveELX(pos));
return newx;
}
int newY(int oldy)
{
int newy = oldy*(1-SmoothMoveELX(pos))
+ 10 *SmoothMoveELX(pos));
return newy;
}
double SmoothMoveELX(double x)
{
double PI = Atan(1) * 4;
return ((cos(1 - x) * PI + 1) /2 )
}
My advice is to take a look on the "verlet integration". It is a quite easy way to simulate basic mechanics. Google for it and you'll find many examples for it, including collision detection and friction. On the long run this will give you more natrual results then estimating the velocity or the new position with a sine function.
Related
I'm writing a 2d game in which an agent has to go to anywhere of large map, automatically.
Ofcourse, the map's got lots of obstacles, geometries, etc.
I decided to implement it with NavGraph (Navigation Graph), and read a very useful, great article here
After a few minutes, I worried about creating nav graph manually.
I googled hours to look up NavGraph generation tools, but there was nothing. (all result was for NavMesh, not NavGraph)
Is there anybody help me? Any suggestion or reply will be appreciated.
Thanks.
I used libpedsim
It provides a framework to set waypoints and obstacles:
Ped::Tscene* pedscene;
Ped::Twaypoint* w1;
Ped::Tobstacle* o;
Waypoints were simply created by random sampling - we created a texture where red means it is blocked and otherwise the cell is free. The hacky implementation looked like this and worked pretty well:
// setup
pedscene = new Ped::Tscene(-200, -200, 400, 400);
loadMap();
srand(time(NULL));
int x;
int y;
for (int i = 0; i<agnentCount_/10; i++)
{
Ped::Tagent *a = new Ped::Tagent();
while(true)
{
x = rand() % 99;
y = rand() % 99;
if(texData[y * tex_->getWidth() + x][0]==255)
{
break;
}
}
a->setPosition(
x,
-y,
0.2);
while(true)
{
x = std::rand() % 99;
y = std::rand() % 99;
if(texData[y * tex_->getWidth() + x][0]==255)
{
break;
}
}
PathFind seeker(
a->getPosition().x,
-a->getPosition().y,
x,
y,
tex_->getWidth(),
tex_->getHeight(),
texData);
std::vector<buw::vector2i> path;
path = seeker.findPath();
for(std::vector<buw::vector2i>::iterator it = path.begin(); it!=path.end(); it++)
{
w1 = new Ped::Twaypoint( it->x(), -it->y(), 5);
a->addWaypoint(w1);
}
pedscene->addAgent(a);
I'm trying to emulate the following ball. Notice the simple harmonic motion of the ball, with the very ends of the ball bounce having a smaller velocity compared to the velocity in the middle:
I'm able to implement a bouncing ball, however it's not simple harmonic motion:
The corresponding code is as follows:
Dot::Dot() {
//Initialize the offsets
mPosX = 300;
mPosY = 0;
//Initialize the velocity
mVelX = 0;
mVelY = 4;
}
void Dot::move() {
//Move the dot up or down
mPosY += mVelY;
//If the dot went too far up or down
if( ( mPosY < 0 ) || ( mPosY + DOT_HEIGHT > SCREEN_HEIGHT ) )
{
//Move back
mVelY = -mVelY;
}
}
I have a simple harmonic motion model, like so:
The corresponding code is as follows:
Dot::Dot() {
//Initialize the offsets
mPosX = 300;
mPosY = 0;
//Initialize the velocity
mVelX = 0;
mVelY = 0;
}
void Dot::move() {
time_t current_time;
current_time = time(NULL);
mPosY = int(((460) - 10) * sin(2.4 * 2 * 3.141592 / 60 * current_time + (SCREEN_HEIGHT / 2)
));
//const int SCREEN_HEIGHT = 480
}
The issues with this implementation are that:
(1). the ball image appears every now and then, rather than continuously like in the blue ball model I tried to emulate at the very beginning
(2). the ball goes well beyond the top frame of the window, rather than slowing down at the very top of the window, again like the blue ball model.
For (2), I understand that I need to add a phase shift, i.e x in A*sin(wt + x), however changing this value doesn't do anything to prevent the ball from disappearing at the top of the window.
Any ideas on how to solve these issues?
Edit: I was able to solve (1) by doing += to mPosY rather than =, such as:
mPosY += int(4 * cos(2.4 * 2 * 3.141592 / 60 * current_time + (SCREEN_HEIGHT / 2) ));
However, I'm still unable to get the ball to bounce up and down within the frame of the window I created.
I recommend using actual simple harmonic equations.
For example, if your display dimensions are (500, 500), the center Y is 250. from there say your equation is in the form of x = acos(nt + m) + c where x is displacement (meters), a is amplitude n is for the period, for example the period (T) = 2PI/n t is time (seconds) and m is for phase shift and c is for the center. That way when you need the velocity of the object, you have a function that follows along the lines of
double Velocity(double time){
double vel = derivative_of_displacement_equation(time);
return vel;
}
And so in the program, you adjust the equation to suit the display dimensions, then you set the objects X/Y coordinates as the value returned from the displacement equation (PLUS THE CENTER OFFSET, in this example, if the center is at the middle of the screen, you would set the Y coordinate to the equation PLUS 250). Keep in mind coordinates begin at (0,0) so your displacement equation (at least the part where it involves the proportional factor, which in this case is time), you make that negative instead.
Here is some code that I believe answers your question:
#include <SDL2/SDL.h>
#include <chrono>
#include <math.h>
#include <iostream>
const double PI = 3.14159265358979;
void draw_circle(SDL_Renderer *renderer, int x, int y, int radius, SDL_Color color)
{
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
for (int w = 0; w < radius * 2; w++)
{
for (int h = 0; h < radius * 2; h++)
{
int dx = radius - w; // horizontal offset
int dy = radius - h; // vertical offset
if ((dx*dx + dy*dy) <= (radius * radius))
{
SDL_RenderDrawPoint(renderer, x + dx, y + dy);
}
}
}
}
double Displacement(double time, double a, double n, double m, double c)
{
double displacement = a*cos(n*time + m) + c;
return displacement;
}
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("SHM", 0, 30, 500, 500, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED );
double timeDifference;
std::chrono::steady_clock::time_point start, finish;
start = std::chrono::steady_clock::now();
finish = start;
SDL_Event event;
bool running = true;
while (running){
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT){
running = false;
break;
}
}
SDL_SetRenderDrawColor(renderer, 255,255,255,255);
SDL_RenderClear(renderer);
finish = std::chrono::steady_clock::now();
timeDifference = std::chrono::duration_cast<std::chrono::nanoseconds>(finish - start).count();
timeDifference = timeDifference / 1000000000;
///The "-(250-20) is the center y (250) minus the radius of the circle (20), and its - out the front as negative a due to coordinates
double yPosition = round( Displacement(timeDifference, -(250-20), 2, 0, 250 ) );
draw_circle(renderer, 250, yPosition, 20, {255,0,0});
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
In general you have a0 + a/2*cos (2*𝝥*t/T + 𝝫) where a0 is the vertical position of the half of the vertical travel, a is the height of the travel, t is time, T the period ie., the time to do a complete cycle for going and coming back to the same state or uple { position, momentum }, and 𝝫 the time shift, ie., the moment where the height is at zero of the cos.
So if you want the ball to be on the floor at t=0, you want cos at the minimum, ie., 𝝫 = -𝝥/2.
You want to manage your position in function of your game's time t, so you can decouple the time to compute (which depend on your compute calpabilities) and the game's time (that you want constant from a machine to another).
Therefore you want:
auto VerticalPosition(double t)
-> double { return CorrectedScreenHeight/2*(1 + cos(2*PI*t/T + phi)); }
And you define CorrectedScreenHeight = SCREEN_HEIGHT - DOT_HEIGHT, T and phi outside, as properties of your system.
Between two consecutive images, you increment t, in order to have the correct experienced time. Typically you have 60 images/s (WPF, DirectX, web, etc), hence a period of 1.0/60s between consecutive images, this goes in your function that modifies t. The speed of your ball then depend on T, that you can tune independently.
I am making a game in OpenGL with C++. I have a terrain that has hills and such and I want the character to be able to walk up and down the hill. To do this I have made a function that tries to find the the closest coordinates and return the corresponding y coordinates but its isn't working, my character is just staying at the same height. Here is my function:
float ViewPort::comparePosition(float xPos, float zPos) {
int closestValSoFar = 0;
for (int unit = 0; unit < sizeof(desert_scene_plainVerts)/sizeof(desert_scene_plainVerts[0]); unit++){
int xDifference = terrainxPos[unit] - xPos;
int zDifference = terrainzPos[unit] - zPos;
int combinedDifferece = xDifference + zDifference;
if (unit == 0) {
closestValSoFar = unit;
}
if (combinedDifferece < (terrainxPos[unit-1] - xPos) + (terrainzPos[unit-1] - zPos)) {
closestValSoFar = unit - 1;
}
else {
closestValSoFar = unit;
}
if ((unit - 1) < sizeof(desert_scene_plainVerts)/sizeof(desert_scene_plainVerts[0])) {
return terrainyPos[closestValSoFar];
}
}
return terrainyPos[closestValSoFar];
}
I am calling this and using it with this code:
float yPos = ViewPort::comparePosition(Camera::position.x, Camera::position.z);
Camera::position.y = yPos+1.65;
Does anybody know how I can fix my code?
If I understood you correctly, you're trying to perform terrain clamping by comparing the position of the object and the terrain height at the given position; but the most common way to do this is by performing ray casting from the object's position to the terrain. Then you check if the ray intercepts the terrain and where it happens.
But making a game from openGL is really hard, why don't you try a 3d engine like OGRE?
If you are planning to do it this way, as I do like this simple method, I would simply rewrite the function a little bit. Honestly I think your method can be simplified a little more.
I made a few modifications and placed it here. I changed the adding to Pythagorean Theorem for a slight increase in accuracy, but if it causes a significant loss in performance, I'm sure that the old adding would work nearly as well as the new method.
float ViewPort::comparePosition(float xPos, float zPos) {
int closestValSoFar = 0;
for (int unit = 0; unit < sizeof(desert_scene_plainVerts)/sizeof(desert_scene_plainVerts[0]); unit++){
int xDifference = terrainxPos[unit] - xPos;
int zDifference = terrainzPos[unit] - zPos;
int combinedDifferece = sqrt(xDifference*xDifference + zDifference*zDifference);
if (unit == 0) {
closestValSoFar = unit;
}
else if (combinedDifferece < closesValSoFar) {
closestValSoFar = combinedDifference;
}
}
return terrainyPos[closestValSoFar];
}
Honestly I really liked that old code and this is virtually the same, I simply checked whether the new distance is less than the closestValSoFar instead of the vertex before. I hope this helps!
I appreciate your endeavor to make a game with plain OpenGL, as I too deny engines (for what reason I don't know, I just find them boring. I'm not an artist, I'm a programmer, and engines are into artists and simplifying stuff)! I'd love to see your finished product, sounds cool!
Learning SFML and making a game in C++ for the first time. My problem comes with movement of the character. I'm making an Astroids-like clone, and the movement, when the keys are pressed, aren't very smooth. The character stutters around, and stops when rotating and moving forward are pressed at the same time. Any help?
Player.cpp
#include "Player.h"
#include "Bullet.h"
#include <iostream>
#include <valarray>
#define SPEED 10
#define ROTATION 15
Player::Player()
{
this->_x = 150;
this->_y = 150;
this->_xspeed = 0;
this->_yspeed = 0;
this->_rotation = ROTATION;
this->_user = this->loadSprite("/Users/ganderzz/Desktop/Programming/C_Plus/stest/stest/Resources/Player.png");
this->_user.setOrigin(16, 16);
}
void Player::Collision(RenderWindow & in)
{
if(this->_x >= (in.getSize().x-32) || this->_x <= 0)
this->_xspeed = 0;
}
void Player::Move(Event & e)
{
if(Keyboard::isKeyPressed(Keyboard::D))
{
this->_user.rotate(this->_rotation);
}
if(Keyboard::isKeyPressed(Keyboard::A))
{
this->_user.rotate(-this->_rotation);
}
if(Keyboard::isKeyPressed(Keyboard::W))
{
this->_yspeed = -sinf((90 + this->_user.getRotation()) * 3.14 / 180) * SPEED;
this->_xspeed = -cosf((90 + this->_user.getRotation()) * 3.14 / 180) * SPEED;
this->_x += this->_xspeed;
this->_y += this->_yspeed;
}
if(Keyboard::isKeyPressed(Keyboard::Space))
{
Bullet b(this->_x,this->_y,this->_user.getRotation());
}
}
void Player::Draw(RenderWindow & in)
{
this->_user.setPosition(this->_x, this->_y);
in.draw(this->_user);
}
Sprite Player::loadSprite(std::string filename)
{
this->_texture.loadFromFile(filename, IntRect(0,0,32,32));
return Sprite(this->_texture);
}
I think it is due to time management, if it is a small 2D you probably have a high FPS rate.
And then your move event is call way to many times and create this stutter.
You should limit you framerate, and try to add a clock to your event if limiting framerate is not enough.
You can find what you need in this page of the doc
If it is not that at all, show us your main loop, maybe you have something taking a lot of ressources there.
Hope it helps.
{Hopefully improved my post, please still suggest any other code you need, and once again im sorry for being so clueless, im determined to get past this problem though so i truly appreciate your time!!!}
**EDIT: thanks to Frank with his reply below, the program now starts and draws the three enemies, but just a few second later crashes, the program code below therefore is still applicable as its basically the move loop and somewhere in there something is still going wrong.
I realise this is extremely obscure and i have tried my best to explain it, but if noone can advise then the few second its up should be enough to complete the tutorial anyway and ill dissect the whole project after its finished and really try and break it down and learn as much as possible.**
Okay, so I run this loop designed to create new enemies, and then draw them onto the screen, it now works, but after a few second crashes. below is the steps the debugging goes through and the call stack at the end if what it displayed after the crash. hope you can help!
this is a video tutorial im following and im stuck, cant find the answer. checked the code over and over again. (the full code is at the bottom of the post (codeblocks,) but i have tried to include as much info as possible in this post)
the function is:
level->addEnemies(3);
which looks like in the main game.cpp:
bool Game::run(void)
{
level = new Level(&drawArea, 30, 20);
drawArea.createBackgroundTile(TILE_EMPTY, ' ');
drawArea.createBackgroundTile(TILE_WALL, 219);
drawArea.createSprite(SPRITE_PLAYER, 1);
drawArea.createSprite(SPRITE_ENEMY, '$');
player = new Character(level, &drawArea, 0);
level->draw();
level->addPlayer(player);
level->addEnemies(3); <-------- SKIPS TO THIS FUNC
char key = ' ';
startTime = timeGetTime();
frameCount = 0;
lastTime = 0;
posx = 0;
player->move(0,0);
while (key != 'q')
{
while (!getInput(&key))
{
timerUpdate();
}
level->keyPress(key);
}
delete player;
return true;
}
the function in full is below, note that when i remove this addEnemies function from the main game loop everything runs perfectly fine with no crash, so it has something to do with the upcoming functions.
void Level::addEnemies(int num)
{
int i = num;
while (i > 0)
{
int xpos = int(float(rand() % 100) / 100) * (width - 2) + 1;
int ypos = int(float(rand() % 100) / 100) * (height - 2) + 1;
if (level[xpos][ypos] != TILE_WALL)
{
Enemy *temp = new Enemy(this, drawArea, SPRITE_ENEMY,
(float)xpos, float(ypos));
temp->addGoal(player);
addNPC((Sprite *)temp);
i--;
}
}
}
It gets through this function without any problems it seems.
After this function is goes back to the game loops and executes through fine, goes into timer update without any problems. Here is the timerUpdate function:
void Game::timerUpdate(void)
{
double currentTime = timeGetTime() - lastTime;
if (currentTime < GAME_SPEED)
return;
level->update(); <--------SKIPS TO THIS FUNC
frameCount++;
lastTime = timeGetTime();
}
This is the Level->Update() Func:
void Level::update(void)
{
for (Iter = npc.begin(); Iter != npc.end(); Iter++)
{
(*Iter)->idleUpdate(); <-------------SKIPS TO THIS FUNC
if ((*Iter)->isAlive() == false)
{
Sprite *temp = *Iter;
//kill the enemy
Iter--;
delete temp;
npc.remove(temp);
}
}
}
idleUpdate():
void Enemy::idleUpdate(void)
{
if (goal)
simulateAI(); <------ Goes to this func
}
simulateAI():
void Enemy::simulateAI(void)
{
vector goal_pos = goal->getPosition();
vector direction;
direction.x = goal_pos.x - pos.x;
direction.y = goal_pos.y - pos.y;
float mag = sqrt(direction.x * direction.x + direction.y * direction.y);
direction.x = direction.x / (mag);
direction.y = direction.y / (mag);
if (!move(direction.x, direction.y)) <------ SKIPS TO THIS FUNC
{
while (!move(rand() % 3 - 1, rand() % 3 - 1))
{
}
}
move function:
bool Sprite::move(float x, float y)
{
int xpos = (int)(pos.x +x);
int ypos = (int)(pos.y +y);
if (isValidLevelMove(xpos,ypos)) SKIPS TO THIS FUNC
{
//.....rest not needed
isValidMove func:
bool Sprite::isValidLevelMove(int xpos, int ypos)
{
if (level->level[xpos][ypos] != TILE_WALL) <-------------THIS LINE CRASHES!!
return true;
return false;
}
I really cant figure out where this goes wrong, and why at the end the call stakc shows such high out of bounds numbers for xpos adn ypos.
Here is the full call stack:
#0 00402920 Sprite::isValidLevelMove (this=0x791498, xpos=-2147483648, ypos=-2147483648) (sprite.cpp:95)
#1 00000000 0x00401750 in Enemy::move (this=0x791498, x=-nan(0x400000) (enemy.cpp:21)
#2 00401892 Enemy::simulateAI (this=0x791498) (enemy.cpp:67)
#3 004017E5 Enemy::idleUpdate (this=0x791498) (enemy.cpp:46)
#4 0040226E Level::update (this=0x792e90) (level.cpp:86)
#5 00401CB8 Game::timerUpdate (this=0x28fec0) (game.cpp:93)
#6 00401BB5 Game::run (this=0x28fec0) (game.cpp:54)
#7 0040258D main() (main.cpp:11)
which basically tells me xpos and ypos have been mutilated from somehere in thsi proccess and thats causeing the crash im sure because its way out of bounds from the [30][20] int array of the width and height of the drawengine.
ANOTHER EDIT:
Here is the Sprite class, if it helps, will edit in more if needed.
enum
{
SPRITE_CLASSID,
CHARACTER_CLASSID,
ENEMY_CLASSID
};
struct vector
{
float x;
float y;
};
class Sprite
{
public:
Sprite(Level *l, DrawEngine *de, int s_index, float x = 1, float y = 1, int i_lives = 1);
~Sprite();
vector getPosition(void);
float getX(void);
float getY(void);
virtual void addLives(int num = 1);
int getLives(void);
bool isAlive(void);
virtual void idleUpdate(void);
virtual bool move(float x, float y);
protected:
Level *level;
DrawEngine *drawArea;
vector pos;
int spriteIndex;
int numLives;
int classID;
vector facingDirection;
void draw(float x, float y);
void erase(float x, float y);
bool isValidLevelMove(int xpos, int ypos);
};
anyway any help and i would be sooooo grateful, i know i must seem totally useless, but i rteally am determined to learn, and any help you guys can provide would be priceless!!!!
full code file (codeblocks) : http://www.mediafire.com/?5xz2seadmagbetb
This might not be the actual problem, but could be related. Your code to create a random position within your Level::addEnemies(int num) function will always return 1 for xpos and ypos.
This is because of the way you apply the casts. You seem to miss parenthesis for your final cast to int. I think you want something like this:
int xpos = int((float(rand() % 100) / 100) * (width - 2)) + 1;
Update:
The code causing the crash is located in your simulateAI() function. With:
float mag = sqrt(direction.x * direction.x + direction.y * direction.y);
You calculate the distance between two points, but if the points have the same coordinates, the distance is 0.
Later with: direction.x = direction.x / (mag); you devide by this potential 0 and as a result your coordinates will contain NaN. Within your bool Sprite::move(float x, float y) function you cast these NaNs into an int which will give you some undefined number. With this number you are trying to access your array which will lead to the access violation that crashes your program.
So first thing to do is to check for a zero distance and handle that differently.