This is my player's update function:
void update() {
IsOnWall = false;
IsOnFloor = false;
int collide[4] = { collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, vel.y + 1}, Stillbodies),
collidelist(Rect{pos.x, pos.y + hitbox.height, hitbox.width, vel.y - 1}, Stillbodies),
collidelist(Rect{pos.x + vel.x, pos.y + 1, vel.x - 1, hitbox.height - 1}, Stillbodies),
collidelist(Rect{pos.x + hitbox.width, pos.y + 1, vel.x + 1, hitbox.height - 1}, Stillbodies) };
if (collide[0] >= 0 && vel.y <= 0) {
vel.y = 0;
pos.y = Stillbodies[collide[0]].y + Stillbodies[collide[0]].height;
IsOnFloor = true;
}
if (collide[1] >= 0 && vel.y > 0) {
vel.y = 0;
pos.y = Stillbodies[collide[1]].y - Stillbodies[collide[1]].height;
}
if (collide[2] >= 0 && vel.x <= 0) {
vel.x = 0;
pos.x = Stillbodies[collide[2]].x + Stillbodies[collide[2]].width;
IsOnWall = true;
}
if (collide[3] >= 0 && vel.x > 0) {
vel.x = 0;
pos.x = Stillbodies[collide[3]].x - hitbox.width;
IsOnWall = true;
}
IsOnWallOnly = (IsOnWall && !IsOnFloor);
IsOnFloorOnly = (IsOnFloor && !IsOnWall);
pos.x += vel.x;
pos.y += vel.y;
hitbox.x = pos.x;
hitbox.y = pos.y;
}
The if collide[0]
part works most of the time, but if my player's y
velocity is exactly the height of the object it's colliding with, it clips the player in for 1 frame. At least, that's what I've found so far. All the other if
s work perfect, even under the same circumstances.
Here is a minimal reproducible example:
Code
#include <iostream>
#include <deque>
class Rect {
public:
int x;
int y;
int width;
int height;
Rect(int X, int Y, int WIDTH, int HEIGHT) {
x = X;
y = Y;
width = WIDTH;
height = HEIGHT;
}
};
class Spot {
public:
int x;
int y;
Spot(int x1, int y1) {
x = x1;
y = y1;
}
};
bool colliderect(Rect rect1, Rect rect2) {
return (rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y);
}
int collidelist(Rect rect, std::deque<Rect> rects) {
for (float rec = 0; rec < rects.size(); rec++) {
if (colliderect(rect, rects[rec])) {
return rec;
}
}
return -1;
}
std::deque<Rect> Stillbodies = { {0, 0, 50, 50} };
int main() {
Spot pos = Spot(0, 50);
Rect hitbox = Rect(pos.x, pos.y, 50, 50);
Spot vel = Spot(0, 0);
while (true) {
char move;
std::cin >> move;
if (move == 'u') {
vel.y = -50;
}
else if (move == 'd') {
vel.y = 50;
}
else {
vel.y = 0;
}
int collide[4] = { collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, vel.y + 1}, Stillbodies),
collidelist(Rect{pos.x, pos.y + hitbox.height, hitbox.width, vel.y - 1}, Stillbodies),
collidelist(Rect{pos.x + vel.x, pos.y + 1, vel.x - 1, hitbox.height - 1}, Stillbodies),
collidelist(Rect{pos.x + hitbox.width, pos.y + 1, vel.x + 1, hitbox.height - 1}, Stillbodies) };
//broken collision (other ones that look same work)
if (collide[0] >= 0 && vel.y <= 0) {
vel.y = 0;
pos.y = Stillbodies[collide[0]].y + Stillbodies[collide[0]].height;
}
//this one works
if (collide[1] >= 0 && vel.y > 0) {
vel.y = 0;
pos.y = Stillbodies[collide[1]].y - hitbox.height;
}
pos.x += vel.x;
pos.y += vel.y;
hitbox.x = pos.x;
hitbox.y = pos.y;
std::cout << pos.x << " " << pos.y << std::endl;
}
return 0;
}
Input/Output (with added comments)
n //n is just an example for nothing
0 50 //nothing happens. wow
u // u for up
0 0 //you go up but the block is there
n //nothing
0 50 //it pushes you out
u //up
0 0 // same outcome
u //up
0 -50 // now above block, yo can waltz through in the actual game too
d //down
0 -50 // collision working
d //down
0 -50 //double checking
This is my player's update function:
void update() {
IsOnWall = false;
IsOnFloor = false;
int collide[4] = { collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, vel.y + 1}, Stillbodies),
collidelist(Rect{pos.x, pos.y + hitbox.height, hitbox.width, vel.y - 1}, Stillbodies),
collidelist(Rect{pos.x + vel.x, pos.y + 1, vel.x - 1, hitbox.height - 1}, Stillbodies),
collidelist(Rect{pos.x + hitbox.width, pos.y + 1, vel.x + 1, hitbox.height - 1}, Stillbodies) };
if (collide[0] >= 0 && vel.y <= 0) {
vel.y = 0;
pos.y = Stillbodies[collide[0]].y + Stillbodies[collide[0]].height;
IsOnFloor = true;
}
if (collide[1] >= 0 && vel.y > 0) {
vel.y = 0;
pos.y = Stillbodies[collide[1]].y - Stillbodies[collide[1]].height;
}
if (collide[2] >= 0 && vel.x <= 0) {
vel.x = 0;
pos.x = Stillbodies[collide[2]].x + Stillbodies[collide[2]].width;
IsOnWall = true;
}
if (collide[3] >= 0 && vel.x > 0) {
vel.x = 0;
pos.x = Stillbodies[collide[3]].x - hitbox.width;
IsOnWall = true;
}
IsOnWallOnly = (IsOnWall && !IsOnFloor);
IsOnFloorOnly = (IsOnFloor && !IsOnWall);
pos.x += vel.x;
pos.y += vel.y;
hitbox.x = pos.x;
hitbox.y = pos.y;
}
The if collide[0]
part works most of the time, but if my player's y
velocity is exactly the height of the object it's colliding with, it clips the player in for 1 frame. At least, that's what I've found so far. All the other if
s work perfect, even under the same circumstances.
Here is a minimal reproducible example:
Code
#include <iostream>
#include <deque>
class Rect {
public:
int x;
int y;
int width;
int height;
Rect(int X, int Y, int WIDTH, int HEIGHT) {
x = X;
y = Y;
width = WIDTH;
height = HEIGHT;
}
};
class Spot {
public:
int x;
int y;
Spot(int x1, int y1) {
x = x1;
y = y1;
}
};
bool colliderect(Rect rect1, Rect rect2) {
return (rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y);
}
int collidelist(Rect rect, std::deque<Rect> rects) {
for (float rec = 0; rec < rects.size(); rec++) {
if (colliderect(rect, rects[rec])) {
return rec;
}
}
return -1;
}
std::deque<Rect> Stillbodies = { {0, 0, 50, 50} };
int main() {
Spot pos = Spot(0, 50);
Rect hitbox = Rect(pos.x, pos.y, 50, 50);
Spot vel = Spot(0, 0);
while (true) {
char move;
std::cin >> move;
if (move == 'u') {
vel.y = -50;
}
else if (move == 'd') {
vel.y = 50;
}
else {
vel.y = 0;
}
int collide[4] = { collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, vel.y + 1}, Stillbodies),
collidelist(Rect{pos.x, pos.y + hitbox.height, hitbox.width, vel.y - 1}, Stillbodies),
collidelist(Rect{pos.x + vel.x, pos.y + 1, vel.x - 1, hitbox.height - 1}, Stillbodies),
collidelist(Rect{pos.x + hitbox.width, pos.y + 1, vel.x + 1, hitbox.height - 1}, Stillbodies) };
//broken collision (other ones that look same work)
if (collide[0] >= 0 && vel.y <= 0) {
vel.y = 0;
pos.y = Stillbodies[collide[0]].y + Stillbodies[collide[0]].height;
}
//this one works
if (collide[1] >= 0 && vel.y > 0) {
vel.y = 0;
pos.y = Stillbodies[collide[1]].y - hitbox.height;
}
pos.x += vel.x;
pos.y += vel.y;
hitbox.x = pos.x;
hitbox.y = pos.y;
std::cout << pos.x << " " << pos.y << std::endl;
}
return 0;
}
Input/Output (with added comments)
n //n is just an example for nothing
0 50 //nothing happens. wow
u // u for up
0 0 //you go up but the block is there
n //nothing
0 50 //it pushes you out
u //up
0 0 // same outcome
u //up
0 -50 // now above block, yo can waltz through in the actual game too
d //down
0 -50 // collision working
d //down
0 -50 //double checking
Share
Improve this question
edited Nov 21, 2024 at 21:15
mkrieger1
23.3k7 gold badges64 silver badges81 bronze badges
asked Nov 21, 2024 at 6:47
jg1121jg1121
254 bronze badges
9
|
Show 4 more comments
1 Answer
Reset to default 0I found out the issue; When the velocity is negative, I wasn't flipping it yet was accounting for it as if it was negative.
collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, vel.y + 1}, Stillbodies),//issue here
collidelist(Rect{pos.x, pos.y + hitbox.height, hitbox.width, vel.y - 1}, Stillbodies),
collidelist(Rect{pos.x + vel.x, pos.y + 1, vel.x - 1, hitbox.height - 1}, Stillbodies),
collidelist(Rect{pos.x + hitbox.width, pos.y + 1, vel.x + 1, hitbox.height - 1}, Stillbodies) };
I changed it to this
{ collidelist(Rect{pos.x, pos.y + vel.y, hitbox.width, -vel.y + 1}, Stillbodies)
_____________________________________________________^ Negative velocity
moveup()
,moveleft()
). Consider also adding some output of interesting variables. Your venting ("grr") I totally understand and do not consider them a problem in your question, but they might be perceived differently by other users. – Yunnosch Commented Nov 21, 2024 at 7:22if
withinupdate()
something likeIsAtCeil
, just to complete the pattern. Please explain why it is not there. I do see by the way that floor and wall do not have an influence, it just triggers my desire for complete patterns.... – Yunnosch Commented Nov 21, 2024 at 7:33