Collision GameMaker issue - game-maker

I'm new to GameMaker and I followed a tutorial by "Let's Learn This Together". I was trying to make collisions for my character, however every time my character bumps into the object, they get stuck and I can't control them anymore. I checked many times and I tried my own ideas, but nothing worked.
if(keyboard_check(ord("D")) && place_free(x + collisionSpeed, y)) {
x += walkSpeed;
image_speed = walkSpeed / 3;
sprite_index = sClaire_Side_Right;
}
if(keyboard_check(ord("A")) && place_free(x - collisionSpeed, y)) {
x -= walkSpeed;
image_speed = walkSpeed / 3;
sprite_index = sClaire_Side_Left;
}
if(keyboard_check(ord("W")) && place_free(x, y - collisionSpeed)) {
y -= walkSpeed;
image_speed = walkSpeed / 3;
sprite_index = sClaire_Normal_Back;
}
if(keyboard_check(ord("S")) && place_free(x, y + collisionSpeed)) {
y += walkSpeed;
image_speed = walkSpeed / 3;
sprite_index = sClaire_Normal;
}
if(keyboard_check(vk_shift)) {
walkSpeed = 7;
}
if(keyboard_check(vk_nokey)) {
image_speed = 0;
image_index = 0;
walkSpeed = 3.5;
}

If you're moving instnace by walkSpeed, you should also check for collision in distance of walkSpeed, not collisionSpeed.
If collisionSpeed is smaller than walkSpeed by just 1 pixel, then it might return no collision as it will be last pixel before collision happens.
A good example is when walkSpeed=3, and collisionSpeed=2, which will for sure causes instance to stuck inside solid objects.

Related

Projectiles In Gamemaker Studio 2 Not Moving

My gun's begin step code:
if (global.night == true) {
image_angle = point_direction(x, y, mouse_x, mouse_y);
image_index = 1;
alarm[0] = 0.5 * room_speed;
firingdelay -= 1;
if (mouse_check_button_pressed(mb_left)) && (firingdelay < 0) {
firingdelay = 10;
with (instance_create_layer(Revolver.x+12, Revolver.y, "Bullets", Bullet)) {
direction = Revolver.image_angle;
speed = 25;
image_angle = direction;
}
}
}
It creates the bullets, but they don't move. Can anyone help?
If you have physics enabled in a room, the regular speed and direction variables will not work. Do you have physics enabled? The code looks fine.

Which is more efficient in OpenCL: if conditions or for loops?

I have a piece of OpenCL code like this
if (Sum[0] < Best)
{
Best = Sum[0];
iBest = 1;
*aBits = Bits[0];
}
if (Sum[1] < Best)
{
Best = Sum[1];
iBest = 2;
*aBits = Bits[1];
}
if (Sum[2] < Best)
{
Best = Sum[2];
iBest = 3;
*aBits = Bits[2];
}
if (Sum[3] < Best)
{
Best = Sum[3];
iBest = 4;
*aBits = Bits[3];
}
if (Sum[4] < Best)
{
Best = Sum[4];
iBest = 5;
*aBits = Bits[4];
}
if (Sum[5] < Best)
{
Best = Sum[5];
iBest = 6;
*aBits = Bits[5];
}
if (Sum[6] < Best)
{
Best = Sum[6];
iBest = 7;
*aBits = Bits[6];
}
if (Sum[7] < Best)
{
Best = Sum[7];
iBest = 8;
*aBits = Bits[7];
}
In order to reduce the logic, I rewrote the code like this
for(i = 1; i < 8; i++)
{
if(Sum[i] < Sum[index])
index = i;
}
if (Sum[index] < Best)
{
Best = Sum[index];
iBest = index + 1;
*aBits = Bits[index];
}
But, in the second case the latency increased, by about 20%. Can anybody provide any insight into this kind of behavior? Is the if conditions style of coding more efficient than for loops in OpenCL?
I'm using Intel 530 (Gen9) GPU. I'm using memory mapped access.
The first case is bad for a GPU. Since it forces that when one of the work items enters an if condition all of them do.
If you expect random entering the "if" conditions, in the end all instructions are executed and they are more than in the second case.
While on the second case, the GPU instructions inside the "if" are less, only one liners. And all the work items enter the last section at the same time.
For a CPU the first case is best, since there is no need to save an index and then look it up.
In any case, avoid double/tripple reading variables on the global memory. Because those are not optimized by the compiler (unless marked as read_only). This code should be much faster to what you wrote:
int best_sum = Sum[index]; //Private, fast access
for(i = 1; i < 8; i++)
{
int sum = Sum[i]; //Again private
if(sum < best_sum){
index = i;
best_sum = sum;
}
}
if (best_sum < Best)
{
Best = best_sum;
iBest = index + 1;
*aBits = Bits[index];
}

Collision detection is not working correctly

I have to submit a Breakout clone and I'm struggling with the collision detection of the ball and the bricks. Basically, the collision detection works, but the ball destroys the brick about 10 pixels away from the visual object. I'm checking the bounds of both objects, but I guess the problem is that the ball is a moving object and the brick is a static one.
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
brick = brickArray[i][j];
if (brick == null)
continue;
areBricksLeft = true;
Bounds brickBounds = brick.getBoundsInParent();
Bounds ballBounds = ball.getBoundsInParent();
if (brickBounds.intersects(ballBounds) ) {
brick.removeBrickAt(i, j, brick, brickArray, brickPane);
didHitBrick = true;
}
}
}
Thanks for the hint I found the mistake. I replaced my condition with this:
double ballX = ball.getLayoutX() + ball.getRadius();
double ballY = ball.getLayoutY() + ball.getRadius();
if ((ballX <= brickBounds.getMaxX() - 10 && ballX >= brickBounds.getMinX() -10) &&
(ballY <= brickBounds.getMaxY() - 10 && ballY >= brickBounds.getMinY() - 10)) {
brick.removeBrickAt(i, j, brick, brickArray, brickPane);
didHitBrick = true;
}
Now it is possible to adjust the collision by substracting and adding values to the bounds.

Why is this object in game maker sticking in the wall?

For whatever reason in gamemaker whenever this object (circle) is moving to the left (-x) it will stick into the wall, but when it moves to the right it acts as it should. I'll include pictures of the problem, along with the relevant code. The ball has gravity, and falls properly when on the right wall, but stays in the air on the left wall.
The code is a function that handles gravity/physics for anything that calls it. The top half (Right after isPlayer) is to handle the players gravity, so that can be ignored, but after the "else" is where the relevant code starts
Ball not stuck in wall
Ball stuck in wall
And here is the relevant code:
/*
runPhys(collision object, phys object, xVil, yVil, grav, environment x, environment y, isPlayer(1=player))
*/
obj=argument0;
physObj=argument1;
xVal=argument2;
yVal=argument3;
grav=argument4;
xEnv=argument5;
yEnv=argument6;
isPlayer=argument7;
with physObj{
if(isPlayer = 1){ //can ignore from here to
ySpeed = ySpeed + yVal + grav;
xAcc = xAcc+xVal;
if(xAcc>5){
xAcc = 5;
}
if(xAcc<-5){
xAcc = -5;
}
if(position_meeting(x,y+14,obj)){
xSpeed = 0;
xAcc = 0;
if(xVal = -0.2){
xAcc = -5;
}
if(xVal = 0.2){
xAcc = 5;
}
}
xSpeed = xAcc;
if(xSpeed>0){
if((!position_meeting(x+xSpeed+6,y,obj))&&(!position_meeting(x+xSpeed+6,y+12,obj))&&(!position_meeting(x+xSpeed+6,y-12,obj))){
x = x + xSpeed;
}else{
xSpeed = 0;
xAcc = 0;
}
}else{
if((!position_meeting(x-xSpeed-12,y,obj))&&(!position_meeting(x-xSpeed-12,y+12,obj))&&(!position_meeting(x-xSpeed-12,y-12,obj))){
x = x + xSpeed;
}else{
xSpeed = 0;
xAcc = 0;
}
}
if(ySpeed>0){
if(!position_meeting(x,y+ySpeed+12,obj)){
y = y + ySpeed;
}else{
ySpeed = 0;
}
}else{
if(!position_meeting(x,y-ySpeed-24,obj)){
y = y + ySpeed;
}else{
ySpeed = 0;
}
}
if(position_meeting(x,y+12,obj)){
y = y-1;
}
xSpeed = xSpeed/1.02;
}else{ //here, everything above here can be ignored
ySpeed = ySpeed + yVal + grav;
xSpeed = xSpeed + xVal;
if(xSpeed>0){ //the if below checks 3 positions according to the objects bounding box, in this case its checking the right top, right middle, and right bottom of the sprite
if((!position_meeting(x+xSpeed+(bbox_right-bbox_left)/2,y,obj))&&(!position_meeting(x+xSpeed+(bbox_right-bbox_left)/2,y+(bbox_bottom-bbox_top)/2,obj))&&(!position_meeting(x+xSpeed+(bbox_right-bbox_left)/2,y-(bbox_bottom-bbox_top)/2,obj))){
x = x + xSpeed;
}else{
xSpeed = 0;
xAcc = 0;
}
}else{ //this is where I believe the error to be. The above code handles moving to the right, and the below code handles moving to the left, where my problem is.
if((!position_meeting(x-xSpeed-((bbox_right-bbox_left)/2),y,obj))&&(!position_meeting(x-(xSpeed*2)-((bbox_right-bbox_left)/2),y+(bbox_bottom-bbox_top)/2,obj))&&(!position_meeting(x-(xSpeed*2)-((bbox_right-bbox_left)/2),y-(bbox_bottom-bbox_top)/2,obj))){
x = x + xSpeed;
}else{
xSpeed = 0;
xAcc = 0;
}
}
if(ySpeed>0){ //this is all y movement
if((!position_meeting(x,y+ySpeed+(bbox_bottom-bbox_top)/2,obj))&&(!position_meeting(x+(bbox_right-bbox_left)/2,y+ySpeed+(bbox_bottom-bbox_top)/2,obj))&&(!position_meeting(x-(bbox_right-bbox_left)/2,y+ySpeed+(bbox_bottom-bbox_top)/2,obj))){
y = y + ySpeed;
}else{
ySpeed = 0;
xSpeed = 0;
}
}else{
if((!position_meeting(x,y-ySpeed-(bbox_bottom-bbox_top)/2,obj))&&(!position_meeting(x+(bbox_right-bbox_left)/2,y-ySpeed-(bbox_bottom-bbox_top)/2,obj))&&(!position_meeting(x-(bbox_right-bbox_left)/2,y-ySpeed-(bbox_bottom-bbox_top)/2,obj))){
y = y + ySpeed;
}else{
ySpeed = 0;
xSpeed = 0;
}
}
if(position_meeting(x,y+(bbox_bottom-bbox_top)/2,obj)){
y = y-1;
xSpeed = 0;
}
}
}
I am going to make an educated guess based on what I am seeing. I do not know what your bounding boxes sizes are.
Your code checking for anything to the right of the object is checking a little too far to the left.
Your code checking towards the left of your object isn't checking far enough. If your objects speed is 7 and you are only checking 6 pixels to the left of the object, then you can end up inside the wall, which will allow your code checking to the right to detect a wall.
If you are checking for only certain points and not bounding boxes, then it is possible you are simply passing the object without detecting it, depending on the walls width. I would use collision_rectangle for this sort of thing.
Also I would learn the basics of encapsulation and seperation of concerns. By putting your code into separate functions you make it a lot easier to debug and to read.

Processing2 2D Physics Collision at 90 degree corners

so this is my first post ever on asking a question about programming, so please be patient :)
For a little project in school I made a little physics class, handling collision. Although it worked out fine I still have a bug I couldn't figure out after some hours of searching and I still don't really know where the problem lies in.
For the implementation we used the on Java based language Processing which is used for an introduction to programming and prototyping.
With the a left mouseclick I can spawn some balls which collide pixel-wise with a certain color on the screen. When colliding with a 90 degree corner they just fall through the obstacle. Sadly I can't post a screenshot because of my lack in reputation.
So my question is about what the problem is. Someone I asked said it could be a problem with the dot product I use for calculating the new mirrored velocity, but I couldn't find anything in that direction. I suspect the error lies somewhere in the part where the new velocity is calculated, in the update method of the PhysicsEntity class.
So thanks to everyone who is answering, I am grateful for every useful hint :)
Here is my code, it consists of three classes. I am going to post everything so you can run the code yourself. If you don't have processing you'll need to download it from http://processing.org/ in order to run the code sample below.
Main.pde NOTE: This part is only an example for using my physics class.
ArrayList<PhysicsEntity> entities = new ArrayList<PhysicsEntity>();
boolean mouseClicked = false;
boolean paused = false;
void setup()
{
size(800, 600);
background(0);
frameRate(60);
}
void draw()
{
if (!paused)
{
clear();
float gameTime = 1 / frameRate;
loadPixels();
for (int x = 0; x < width; ++x)
{
for (int y = height - 100; y < height; ++y)
{
pixels[x + y * width] = color(0, 200, 0, 128);
}
}
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < 20; ++y)
{
pixels[x + y * width] = color(0, 200, 0, 128);
}
}
for (int x = 0; x < 100; ++x)
{
for (int y = 0; y < height; ++y)
{
pixels[x + y * width] = color(0, 200, 0, 128);
}
}
for (int x = width - 100; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
pixels[x + y * width] = color(0, 200, 0, 128);
}
}
updatePixels();
if (mousePressed)
{
entities.add(new PhysicsEntity(new Vector2(width / 2, height / 2), new Vector2(random(-100, 100), random(-100, 100)), new Vector2(0.0f, 250.0f)));
}
for (int i = 0; i < entities.size(); ++i)
{
entities.get(i).update(gameTime);
entities.get(i).show();
}
}
}
Vector2.pde NOTE: This class is just necessary for calculting things in the physics class.
class Vector2
{
float a;
float b;
Vector2()
{
a = 0.0f;
b = 0.0f;
}
Vector2(float _a, float _b)
{
a = _a;
b = _b;
}
/* Return exact copy of the vector */
Vector2 Copy()
{
return new Vector2(a, b);
}
Vector2 Add(Vector2 vecB)
{
return new Vector2(a + vecB.a, b + vecB.b);
}
Vector2 Substract(Vector2 vecB)
{
return new Vector2(a - vecB.a, b - vecB.b);
}
/* Scale the vector by a scalar x */
Vector2 Scale(float x)
{
return new Vector2(a * x, b * x);
}
Vector2 Divide(float x)
{
return new Vector2(a / x, b / x);
}
float Dot(Vector2 vecB)
{
return (a * vecB.a + b * vecB.b);
}
float SqrLength()
{
return (pow(a, 2) + pow(b, 2));
}
float Length()
{
return sqrt(SqrLength());
}
boolean Equals(Vector2 vecB)
{
return (a != vecB.a || b != vecB.b) ? false : true;
}
}
Vector2 ZeroVector()
{
return new Vector2(0.0f, 0.0f);
}
PhysicsEntity.pde NOTE: That's the class where actually failed.
class PhysicsEntity
{
Vector2 m_Pos;
Vector2 m_PrevPos;
Vector2 m_Vel;
Vector2 m_Acc;
/* bouncyness in case of collision; gets multiplied with the velocity */
float m_fBouncyness = 1.0f;
color collisionKey = color(0, 200, 0, 128);
public PhysicsEntity(Vector2 _pos, Vector2 _vel, Vector2 _acc)
{
if (_vel == null)
_vel = new Vector2(0.0f, 0.0f);
m_Pos = new Vector2(_pos.a, _pos.b);
m_PrevPos = m_Pos;
m_Vel = _vel;
m_Acc = _acc;
}
public void update(float dt)
{
/* Euler Integration more accurate Version */
/* x = x + vt + 0.5*at^2 */
m_Pos = m_Pos.Add(m_Vel.Scale(dt)).Add(m_Acc.Scale(pow(dt, 2)).Scale(0.5));
/* v = v + at */
m_Vel = m_Vel.Add(m_Acc.Scale(dt));
/* Collision based on color key */
if (isCollidable(m_Pos.a, m_Pos.b, collisionKey))
{
float speed = m_Vel.Length();
if (speed > 0.0f)
{
/* normalized vector of velocity */
Vector2 velNorm = m_Vel.Divide(speed);
/* getting the floor normal */
Vector2 floorNorm = interp(m_Pos, m_PrevPos);
if (!floorNorm.Equals(ZeroVector()))
{
/* mirror velocity on floor normal vector */
/* C = A - (2 * B * (A dot B)) where A is original vector, B the mirror, C result. */
Vector2 mirVel = velNorm.Substract(floorNorm.Scale(2.0f).Scale(velNorm.Dot(floorNorm)));
/* caculate new velocity */
m_Vel = mirVel.Scale(speed).Scale(m_fBouncyness);
/* add to position to move out of collision */
m_Pos = m_Pos.Add(m_Vel.Scale(dt));
}
}
}
m_PrevPos = m_Pos;
}
public void show()
{
ellipse(m_Pos.a, m_Pos.b, 10, 10);
}
public Vector2 interp(Vector2 pos, Vector2 PrevPos)
{
/* Vector from previous position to current position */
Vector2 line = pos.Substract(PrevPos);
float iLength = line.Length();
Vector2 lineFraction = ZeroVector();
/* checks if there the is vectorlength greater zero that connects the current and the previous position */
if (iLength > 0.0f)
lineFraction = line.Divide(iLength);
/* loop from through positions between previous position and current position */
for (int i = 0; i <= iLength; ++i)
{
Vector2 normVec = getNormal(PrevPos.Add(lineFraction.Scale(i)), collisionKey);
if (!normVec.Equals(ZeroVector()))
return normVec;
}
return ZeroVector();
}
}
/* returns normal vector of a 2d landscape in a certain area */
public Vector2 getNormal(Vector2 pos, color col)
{
int area = 10;
/* prevent coordinates from being out of the window */
if (pos.a <= area || pos.a >= width - area || pos.b <= area || pos.b >= height - area)
return ZeroVector();
Vector2 avg = new Vector2();
float loops = 0;
/* loop through an area of pixels */
for (int x = -area; x <= area; ++x)
{
for (int y = -area; y <= area; ++y)
{
if (x*x + y*y <= area*area)
{
float sumX = pos.a + float(x);
float sumY = pos.b + float(y);
/* count collidable pixels in area */
if (isCollidable(sumX, sumY, col))
{
/* add up positions of these pixels */
avg.a += sumX;
avg.b += sumY;
++loops;
}
}
}
}
if (loops == 0)
return ZeroVector();
/* calculate average position */
avg = avg.Divide(loops);
/* calculate length of the vector from initial position to average position */
float avgLength = dist(avg.a, avg.b, pos.a, pos.b);
/* check if avgLenth is zero or in other words: if avg is equals to pos */
if (avgLength == 0.0f)
return ZeroVector();
/* calculate vector(connection vector) from initial position to average position */
Vector2 conVec = pos.Substract(avg);
/* return normalized connection vector */
return conVec.Divide(avgLength);
}
/* method to check if pixel on a certain position is collidable */
public boolean isCollidable(float pixelX, float pixelY, color col)
{
if (pixelX >= width || pixelX < 0 || pixelY >= height || pixelY < 0)
return false;
return pixels[int(pixelX) + int(pixelY) * width] == col;
}
Edit1:
So thanks to the friendly first replay I stripped my code by a few lines :) If there is still a problem with my post let me know!
I cant analyze correctness of your whole physic calculation but in my opinion problem is with calculation of new velocity and :
/* caculate new velocity */
m_Vel = mirVel.Scale(speed).Scale(m_fBouncyness);
/* add to position to move out of collision */
m_Pos = m_Pos.Add(m_Vel.Scale(dt));
Because if you change m_fBouncyness to real value simulating some gravitation (0.8f or less) your problem will never occur but if you change it to some unreal value like 2.0f you will lose all your balls after few bounces.
This indicate problem in algorithm. Your approach consist (in simple) of this steps in loop:
update position of ball
calculate new position
correct position depending on bounce
draw ball
Here can be problem because you calculate new position of ball - this position is out of black box so you calculate average position then new velocity and correct new position. Then draw ball and repeat but what if this new position is also out of the black box? This ball will bounce out of border ... this happens in corner because of calculation of average position (in corner you got far away from black box then at classic border (when you set m_fBouncyness to some bigger value this will happen even on normal border not only in corner!))
Hope this could help you to find your problem.
So finally I've got a solution.
It appears that the answer of Majlik was very helpful. According to his answer I did a few changes which I will explain now.
First of all I put the if-statement if (speed > 0.0f) way up, over the whole movement code so nothing happens anymore if the speed is too low. Of course you can define a certain treshold which works for you.
In addition to that I introduced an else-case, for the if(colliding) statement, in which the movement code is handled, so if the ball is currently colliding it doesn't move at all apart from the collision handling code.
Finally I thought of a new way to move the ball out of the collision. The suggestion of Maljik proved to be right. My previous method didn't move the ball out of the collision at all.
For that I made a while loop which loops as long as the ball is still in collision. In every runthrough the ball gets moved by a normalized vector with the same direction as my mirrored velocity vector. For safety reasons I still got an iterator incrementing every time, so it doesn't end in an infinite loop.
After all the solution was very obvious. But thanks to those who answered.
Below the new changed code:
public void update(float dt)
{
float speed = m_Vel.Length();
if (speed > 0.0f)
{
/* Collision based on color key */
if (isCollidable(m_Pos.a, m_Pos.b, collisionKey))
{
/* normalized vector of velocity */
Vector2 velNorm = m_Vel.Divide(speed);
/* getting the floor normal */
Vector2 floorNorm = interp(m_Pos, m_PrevPos);
if (!floorNorm.Equals(ZeroVector()))
{
/* mirror velocity on floor normal vector */
/* C = A - (2 * B * (A dot B)) where A is original vector, B the mirror, C result. */
Vector2 mirVel = velNorm.Substract(floorNorm.Scale(2.0f).Scale(velNorm.Dot(floorNorm)));
/* caculate new velocity */
m_Vel = mirVel.Scale(speed).Scale(m_fBouncyness);
int it = 0;
Vector2 normMirVel = mirVel.Divide(mirVel.Length());
while (isCollidable(m_Pos.a, m_Pos.b, collisionKey) && it < 100)
{
/* add to position to move out of collision */
m_Pos = m_Pos.Add(normMirVel);
++it;
}
}
}
else
{
/* Euler Integration more accurate Version */
/* x = x + vt + 0.5*at^2 */
m_Pos = m_Pos.Add(m_Vel.Scale(dt)).Add(m_Acc.Scale(pow(dt, 2)).Scale(0.5));
/* v = v + at */
m_Vel = m_Vel.Add(m_Acc.Scale(dt));
}
}
m_PrevPos = m_Pos;
}
Edit: I might that this is not an ideal soluation since the ball gets moved further than it should in this frame. Maybe you should only calculate the necessary distance to move out of collision and add the actual velocity step by step. Also you could compare the current velocity direction to the direction where it should go. If it's already moving in the right direction there is no interference needed.

Resources