Smooth Sidescroller Movement and Collisions

T

Toxicosis

Guest
Greetings,

I'm still making a prototype. Go me. Anyway, I ran into some problems...

Thing is, I started using x=x+5 for movement (and the reverse for the right). Then I noticed it did not allow the player to go right up to a wall if it were within 5 pixels.

So I went with a FOR loop, which checks for a collision within 5 pixels, then within 4, then within 3, and so on, then increments the x by the number of pixels it can move without colliding. It worked, and I managed to get the character moving right up to a wall, leaving a zero pixels gap. It also worked pretty well for allowing the player to walk up slopes, but it seems like I won't be able to keep this one.

Code:
//MOVING RIGHT
//step_move is a variable that allows me to alter the speed quickly.
for (mover=0; mover<step_move ; mover++)
  {
  //Checks for collision one square ahead.
  if !place_meeting(x+1, y, obj_walls)
  {
  //Steps forward, if there is room.
  x++;
  }
  else
  {  
  //Checks for collision one square ahead and one up.
  if !place_meeting(x+1, y-1, obj_walls)
  {
  //Steps forward and up if there is room.
  x++
  y--
  }
  //Stops checking if there isn't room neither ahead nor ahead and above.
  }
  };
(The if inside the else handles slopes of up to 45°)

The problem is, I'd like some events to be triggered by collision (allowing the player to break some blocks by just walking up to them), and when I use this loop, collisions don't trigger. The move_contact_solid function produces the same error.

I tried adding an additional x++ at the end, which allows for colliding, but that creates another problem: when the character is falling, they can stop their fall by clinging to walls. It looks pretty cool, but I'd rather not adopt this glitch as a feature.

Any ideas?
 

jo-thijs

Member
Try the following:

At the place in your code where yu've put:
//Stops checking if there isn't room neither ahead nor ahead and above.

Replace it with this:
else
with obj_walls
if place_meeting(x-1, y, other)
with other
event_perform(ev_collision, obj_walls);
 
T

Toxicosis

Guest
It didn't work, sorry. But it showed me all these keywords, which was a great help.

Using the search function, I think I found what might: using instance_position and then destroying the return for any breakables. Which should all be child of "obj_wall_break".

Here's my code in the end. It heads the movement block. First, it checks if anything's going to break just ahead.

var breaks;
breaks = instance_position(x-step_move, y, obj_wall_break);
with(breaks)
{instance_destroy()}

It checks if there are any obj_wall_break within range, then destroys their instances.

It seems to be working so far. It slows down the player a little though.
 

jo-thijs

Member
Oh yeah, made a little mistake in my previous suggestion.
event_perform(ev_collision, obj_walls);

should have been:
event_perform(ev_collision, other.object_index);

in order to work with inheritance.

However, your code should be even better (it is more direct).
I'm not sure where in your code you've put it though.
You can also make it more condense (and I think instance_place would be better here than instance_position):
Code:
else
    with instance_place(x-1, y, obj_wall_break)
        instance_destroy();
And this would go where my previous code went.

That code might also fix the slowing down, not sure though.
 
T

Toxicosis

Guest
I checked your new version. It works. Thanks!

My version's more direct and it involves a little less checking, but yours has the advantage of allowing properties to be modified with collision events. I can turn obj_wall_break into obj_wall_collidable instead, and make some that break, some that get thrown off, etc. by modifying their response to collision events. If I stick to mine, I'll have to add a WHILE loop that checks for every collidable.

So yours seems more appropriate.

As for the slowing down, it's because I could only break one brick per step: the code's run only once per step, so it takes ONE brick, returns its ID, and breaks it. I'd need a for loop that stops only when there's no more obj_wall_break within range; I tried one, but it didn't work.

I was somewhat confused by how the "other" keyword works... I've reread it now, though, and now I know a bit better what we're talking about. If it becomes necessary to optimize (if I wind up having to check for like ten thousand or so collidable instances every step, for instance... depends on how ambitious I get outside the prototype stage), I might come back to this, but for now, it'll do.
 

jo-thijs

Member
I actually made a mistake,
instance_place(x-1, ...)should have been instance_place(x+1, ...).
Not sure why it was working already, but mayby the sloing down is fixed with this?
 
T

Toxicosis

Guest
No, it works fine the first time. You're getting it a bit backwards, if I checked instance_place at x+1 for every brick after moving the player to their x+1, then I'd check if there's a player to the right of the blocks when they're moving right.
Using your last modification would mean the blocks break when the player moves right up to them, and then turns away. Thank you for your time, jo-thijs. I checked your code that time, and it worked. Modified it slightly, for convenience. Here's the final version. For the record, argument0 is the player's movement per frame. If they move to x+5, all breakables are tested against x-5. If they move to x+50, breakables are tested to x-50, and so on.

Code:
with obj_wall_break                      //Tests all breakables.
  {
  if place_meeting(x-argument0, y, other)                      //Tests whether they're colliding with the player.
  with other                                                 //Returns to the player.
  event_perform(ev_collision, other.object_index);               //Collides them.
  }
event_inherited();                                                     //Prevents overwriting.
The prototype is now fully functional, it just happens that some of the scripts I wrote cause tremendous slowdown. Some frames dip down to 14 fps, making the game reach fps as low as 56 on average. But that's a story for another thread. I'd like to mark this one question as solved.
 
Last edited by a moderator:
Top