Jump to content


Photo
- - - - -

Beautiful collisions in top-down games


  • Please log in to reply
8 replies to this topic

#1 eyeCube

eyeCube

    GMC Member

  • GMC Member
  • 206 posts

Posted 30 June 2012 - 08:09 PM

  • Title: Beautiful collisions in top-down games using motion_add() and arrow key movement
  • Description: Using directional keys to control movement using motion_add() and friction, which adds a realistic look to top-down player movement, and collisions with rectangular walls.
  • GM Version: :GM8:
  • Registered: no
  • File Type: .gmk
  • File Size: 12 kb
  • File Link: http://www.mediafire...fk1joj2ii5bgze2
  • Required Extensions: N/A
  • Required DLLs: N/A
  • Tags: wall collision motion_add motion add arrow keys direction directional w a s d top down top-down topdown friction
Summary
I have had this problem for a long time: creating movement based on motion_add() and the arrow keys (or in this case, W, A, S and D) and friction, with smooth, good-looking collisions against walls in a top-down game. Just yesterday, I found a simple solution after hours of toiling (which makes me feel silly for spending so much time). Keep in mind this has only been tested on bounding boxes of rectangles and squares. Also keep in mind the wall object/parent must be solid unless you modify the code (examples of this are below the code)


//create event of player object

friction = .5
acceleration = 1
max_speed = 5

replace .5 with an amount of friction suitable to your game.


//step event of player object

motion_add(90, keyboard_check(ord('W')) * place_free(x, y - 1) * acceleration)
motion_add(270, keyboard_check(ord('S')) * place_free(x, y + 1) * acceleration)
motion_add(180, keyboard_check(ord('A')) * place_free(x - 1, y) * acceleration)
motion_add(0, keyboard_check(ord('D')) * place_free(x + 1, y) * acceleration)

//this is the same code, but drawn out in if statements

if keyboard_check(ord('W')) == 1
{
     if place_free(x, y - 1)
     motion_add(90, acceleration)
}

if keyboard_check(ord('S')) == 1
{
     if place_free(x, y + 1)
     motion_add(270, acceleration)
}

if keyboard_check(ord('A')) == 1
{
     if place_free(x - 1,y)
     motion_add(180, acceleration)
}

if keyboard_check(ord('D')) == 1
{
     if place_free(x + 1, y)
     motion_add(0, acceleration)
}


if speed > max_speed
{
     speed = max_speed
}

replace ord('W') with vk_up, etc. if you want to use arrow keys.
replace the 1s in the motion_add()s and the 5s in the last line of code with other numbers to suit your game.

//player object: collision event with wall object/parent

x = round(x)
y = round(y)
move_outside_solid(direction - 180, speed)
move_contact_solid(direction, speed)
speed = 0

If I take any piece of this code out, it doesn't work properly so I believe that every single character in the codes belongs there and is in its rightful place. However, I suppose you could do
move_outside_solid(direction,-speed) instead of the move_outside_solid() code I used. I think you could also use move_contact_all() and move_outside_all(), but I wouldn't, because it could cause problems. If you don't want the wall to be solid, I would set solid=1 before the collision, then solid=0 after the collision for the wall object/parent.

This code works PERFECTLY for my game (and I don't use caps lock lightly). If anyone finds a problem with this code that involves what I mentioned, please post below, as I would need to update both this post and my game's code.



The editable GM8 file goes more in-depth and provides an example of the code in action.

I hope the community will benefit from this knowledge as I have.


Edit:
Fixed code to be easier to read and it should work/look better. (I never use spaces in between math signs or commas, and never indent, and never use == signs, I just use = signs. I did that to make it more "correct" and possibly easier to read. I know these are "bad coding habits" but I've got my own method for making code easier to read.) New link should be better-commented.



Also, I had a problem with using the step event code that *doesn't* use the if statements. It can cause problems in that you'll need to add a wall object to the corner every time. This can be avoided, as far as I can tell, by using the code for the step event that is drawn out in if statements instead. It shouldn't be noticeably slower to do it this way.

It has also come to my attention that this code will cause the player to accelerate (gain speed) quicker by moving diagonally. I'll post a fix to this as soon as possible. (Thanks Mr B)




Thank you, icuurd12b42! I never thought this would be a staff pick. It's an honor.

Edited by eyeCube, 05 July 2012 - 09:15 PM.

  • 0

#2 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • Global Moderators
  • 14392 posts
  • Version:GM:Studio

Posted 01 July 2012 - 02:25 AM

short, nice and clean example. Good job!
  • 0

#3 nicktheslayer

nicktheslayer

    GMC Member

  • GMC Member
  • 539 posts
  • Version:Unknown

Posted 05 July 2012 - 04:31 AM

How would i use this if i were using the mouse for movement? Every tutorial i see uses the arrow keys or wasd to check for direction, but im using the mouse to move in this game, (Holding the left mouse button makes the character move toward the cursor). How would i accomodate for this?
  • 0

#4 creators124

creators124

    awesomeliciousmember

  • GMC Member
  • 866 posts
  • Version:GM8

Posted 05 July 2012 - 08:39 AM

How would i use this if i were using the mouse for movement? Every tutorial i see uses the arrow keys or wasd to check for direction, but im using the mouse to move in this game, (Holding the left mouse button makes the character move toward the cursor). How would i accomodate for this?



if (mouse_check_button(mb_left)) == 1
{
 	if place_free(lengthdir_x(point_direction(x,y,mouse_x,mouse_y),1), lengthdir_y(point_direction(x,y,mouse_x,mouse_y),1))
 	motion_add(point_direction(x,y,mouse_x,mouse_y), acceleration)
}

if speed > max_speed
{
 	speed = max_speed
}


hope it works! Posted Image

Edited by creators124, 05 July 2012 - 08:39 AM.

  • 0

#5 Mr B

Mr B

    GMC Member

  • GMC Member
  • 172 posts

Posted 05 July 2012 - 09:04 AM

There is one small problem with the code. The object will accelerate faster when moving diagonally.
  • 0

#6 creators124

creators124

    awesomeliciousmember

  • GMC Member
  • 866 posts
  • Version:GM8

Posted 06 July 2012 - 01:37 AM

There is one small problem with the code. The object will accelerate faster when moving diagonally.

actually I went into debug mode and speed stayed consistent.
might be visually faster but real faster/ ;)
  • 0

#7 Jobo

Jobo

    No neurons left today

  • GMC Member
  • 2405 posts
  • Version:GM:Studio

Posted 06 July 2012 - 10:32 PM

Top-down Collision Script Collection

Edited by Jobo, 06 July 2012 - 10:32 PM.

  • 0

#8 eyeCube

eyeCube

    GMC Member

  • GMC Member
  • 206 posts

Posted 08 July 2012 - 03:47 AM


There is one small problem with the code. The object will accelerate faster when moving diagonally.

actually I went into debug mode and speed stayed consistent.
might be visually faster but real faster/ ;)


You do accelerate faster moving diagonally. You don't move faster in any direction at max speed, but you do accelerate faster diagonally. That's a problem I'll have to fix. I'll update it when I do (might be a few days).


Top-down Collision Script Collection



This is the collision detection script for movement based on moving toward the mouse. Although it could use a little tweaking to look more perfect (move_contact() would be nice)
Thank you for posting this, Jobo.
  • 0

#9 Southman

Southman

    I simply am not here

  • GMC Member
  • 1662 posts
  • Version:GM:Studio

Posted 14 July 2012 - 10:14 PM

When you are going diagonal, multiply the speed by .7 or so.
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users