Jump to content


Photo

how to make collisions in a game with no sprites?


  • Please log in to reply
12 replies to this topic

#1 Pandaboy

Pandaboy

    GMC Member

  • GMC Member
  • 593 posts

Posted 26 October 2010 - 10:14 PM

Hi!
My game has no sprites.
each object creates a script with coordinates (x1,y1,x2,y2,x3,y3 etc...), and then the object draws lines between those points.
Something just struck me -- Collisions. Aren't they sprite based in game maker..? hmm. well that's a problem.
I was thinking about drawing the lines on a surface and make into a collision sprite. However I would
rather find another way, since it is kinda lame, and many of my object will distort & change shape,
so it would be hard to make collision surfaces for those.

Anyone got any ideas?
  • 0

#2 jmac09

jmac09

    GMC Member

  • New Member
  • 64 posts

Posted 26 October 2010 - 10:39 PM

Using both of these should work. I don't know how fast it would work though.
/*
**  Usage:
**      point_in_polygon(x,y,polygon);
**
**  Arguments:
**      x,y        a test point, real
**      polygon    ds_list containing XY coordinate pairs defining
**                 the shape of a polygon
**
**  Returns:
**      TRUE if the point is inside the polygon,
**      FALSE otherwise
**
**  GMLscripts.com
*/
[b]{[/b]
    var x0,y0,polygon,inside;
    var n,i,poly_x,poly_y,x1,x2,y1,y2,m,b,ix,iy;
    x0 = argument0;
    y0 = argument1;
    polygon = argument2;
    inside = false;
    n = ds_list_size(polygon) div 2;
    i = 0;
    repeat (n) [b]{[/b]
        poly_x[i] = ds_list_find_value(polygon, 2*i);
        poly_y[i] = ds_list_find_value(polygon, 2*i+1);
        i += 1;
    [b]}[/b]
    poly_x[n] = poly_x[0];
    poly_y[n] = poly_y[0];
    i = 0;
    repeat (n) [b]{[/b]
        x1 = poly_x[i];
        y1 = poly_y[i];
        x2 = poly_x[i+1];
        y2 = poly_y[i+1];
        if (((y1 <= y0) && (y2 > y0)) || ((y1 > y0) && (y2 <= y0))) [b]{[/b]
            if (x1 == x2) [b]{[/b]
                if (x1 > x0) inside = !inside;
            [b]}[/b]else[b]{[/b]
                m = (y2 - y1) / (x2 - x1);
                b = y1 - m * x1;
                ix = (y0 - b) / m;
                iy = y0;
                if (ix > x0) inside = !inside;
            [b]}[/b]
        [b]}[/b]
        i += 1;
    [b]}[/b]
    return inside;
[b]}
[/b]
/*
**  Usage:
**      t = lines_intersect(x1,y1,x2,y2,x3,y3,x4,y4,segment)
**
**  Arguments:
**      x1,y1,x2,y2     Coordinates defining first line segment
**      x3,y3,x4,y4     Coordinates defining second line segment
**      segment         If TRUE, intersection test is confined to the given line segments
**                      If FALSE, intersection may occur at any point on the given lines
**
**  Returns:
**      The vector multiplier (t) from the parametric form of the first line.
**      A value of 0 < t <= 1 indicates an intersection within the first line segment.
**      A value of 0 indicates no intersection, other values indicate a possible
**      intersection beyond the endpoints of the first line segment.
**
**  Notes:
**      By substituting the return value (t) into the parametric form of the first line,
**      you can determine the point of intersection, eg. x = x1+t*(x2-x1)
**
**  GMLscripts.com
*/
[b]{[/b]
    var x1,y1,x2,y2,x3,y3,x4,y4,segment,ud,ua,ub;
    x1 = argument0;
    y1 = argument1;
    x2 = argument2;
    y2 = argument3;
    x3 = argument4;
    y3 = argument5;
    x4 = argument6;
    y4 = argument7;
    segment = argument8;
    ua = 0;
    ud = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
    if (ud != 0) [b]{[/b]
        ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / ud;
        if (segment) [b]{[/b]
            ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / ud;
            if (ua < 0 || ua > 1 || ub < 0 || ub > 1) ua = 0;
        [b]}[/b]
    [b]}[/b]
    return ua;
[b]}
[/b]
  • 0

#3 thatshelby

thatshelby

    GMC Member

  • GMC Member
  • 3823 posts
  • Version:GM8

Posted 26 October 2010 - 11:12 PM

Search the manual for the collision_* functions.


  • 0

#4 jmac09

jmac09

    GMC Member

  • New Member
  • 64 posts

Posted 26 October 2010 - 11:18 PM

Search the manual for the collision_* functions.

That won't work because there are no sprites to check.
  • 0

#5 thatshelby

thatshelby

    GMC Member

  • GMC Member
  • 3823 posts
  • Version:GM8

Posted 26 October 2010 - 11:19 PM

I don't think it checks for sprites... does it?

If it does...

-Try assigning a mask
-Check coordinates


  • 0

#6 ragarnak

ragarnak

    GMC Member

  • Retired Staff
  • 19468 posts
  • Version:GM8

Posted 27 October 2010 - 08:11 AM

Anyone got any ideas?

I would do as "Theophilus" mentioned, use a collision-mask sprite. Thats by far the easiest solution (lets you use GMs inbuild collision events & commands).
  • 0

#7 MasterOfKings

MasterOfKings

    The True Master

  • GMC Member
  • 4888 posts
  • Version:GM8

Posted 27 October 2010 - 08:25 AM

I don't think it checks for sprites... does it?

It looks for a collision mask; by default, the mask is the same as the sprite, if there's no sprite, then there's no mask.

I would do as "Theophilus" mentioned, use a collision-mask sprite. Thats by far the easiest solution (lets you use GMs inbuild collision events & commands).

It wouldn't be very practical though, as the shapes will be varying shapes (stated in OP). If there's little variance, you can a few masks to do it, but if there's hundreds, it might be better to not have all those masks (unless you know of a way to dynamically edit masks?).

-MoK
  • 0

#8 ragarnak

ragarnak

    GMC Member

  • Retired Staff
  • 19468 posts
  • Version:GM8

Posted 27 October 2010 - 09:20 AM

I would do as "Theophilus" mentioned, use a collision-mask sprite.

It wouldn't be very practical though, as the shapes will be varying shapes (stated in OP).

I was assuming the OP talked about the endpoints themselves, but after re-reading realize that he could be talking about colliding with the lines ... :mellow:

In that latter case "jmac09" showed one possibility. Another could be the point_line_distance(...) from the same site.
  • 0

#9 Pandaboy

Pandaboy

    GMC Member

  • GMC Member
  • 593 posts

Posted 28 October 2010 - 04:58 AM

Wow, this topic got many answers fast ^^!

@Jmac09: even if that big piece of code would work as collision checking, it would probably limit the game's use of collision, since it would probably slow everything down if overused. also, if x1,y1,x2,y2 etc were to be put as arguments, there could not be more than 8 points in each collision check..

-Try assigning a mask
-Check coordinates


@Theo: A collision mask is the same as a sprite. it's a black sprite that the game uses for collision checking. I was trying to avoid sprites.. but maybe I'll have to change my mind about that..
About checking coordinates.. I was thinking about that. Was also trying that out.




@Everyone:
I made a test that checks for collisions. All those codes that checks if lines are intersecting seems too expensive for a game with many objects. In my collision test, i simply made my object that was made of coordinates collide with a ball sprite.. and it worked well. But.. well.. only works with sprites.

So i thought for a while... and the best thing to probably to give all objects a mask. They will deform, yes, but most objects will deform towards their origin, which is placed in the middle (Like when a spaceship collides with a asteroid it gets a dent according to it).
So.. I could draw all different objects on a surface, make a collision mask out of it once, and assign it to each object. Then when collision checking, it will first check if the masks are colliding, then check collision_lines on those sprites. For objects with higher priority, like the player, i could update the collision mask according to it's deformation (of course just once in a while && if it's deformed).

My problem now is.. I have never used surfaces. Does anyone have a good example of drawing to a surface and make a mask of it?
my guess is that it will look something like this (correct me, 'cause I'll be wrong :P):
/*
1. Create a surface
2. Set drawing so it will happen of this surface
3. Draw what I want on the surface
4. stop from drawing on the surface

and when I want a mask:
myMask = sprite_create_from_surface(argument,anotherArgument,and,so,on);
sprite_index = myMask;
*/

But.. more exactly how is it done?

Edited by Pandaboy, 28 October 2010 - 05:01 AM.

  • 0

#10 ragarnak

ragarnak

    GMC Member

  • Retired Staff
  • 19468 posts
  • Version:GM8

Posted 28 October 2010 - 07:38 AM

I made a test that checks for collisions. All those codes that checks if lines are intersecting seems too expensive for a game with many objects.

It depends on what your "many objects" look like : If none of the lines intersect you could simply find the nearest line-endpoint object, and check only the lines connected to it ...

Does anyone have a good example of drawing to a surface and make a mask of it?

You've allmost got it.

Create the surface once, in the create-event using "surface_create(...)".

Switch to drawing on the Surface :
surface_set_target(...)
draw_clear_alpha(...) //so the previous contents are erased

Drawing : Please notice that the upper-right of the Surface is at coordinate 0,0 (which, if you use a View, does not need to match what you are currently seeing on the screen !)

Stop drawing to the Surface :
surface_reset_target(...)

Thats about it. Between the setting of the Surface as the target and resetting it all draw-actions go to the Surface. Specifics can be found in GMs Help.

One remark : You cannot change the draw-target in the draw-event itself.

And you ofcourse need GM Pro for the above ...
  • 0

#11 BassMakesPaste

BassMakesPaste

    GMC Member

  • New Member
  • 20 posts

Posted 28 October 2010 - 08:11 AM

you could try visible=false or collision_(shape)(etc)
  • 0

#12 Pandaboy

Pandaboy

    GMC Member

  • GMC Member
  • 593 posts

Posted 28 October 2010 - 01:38 PM

I made a test that checks for collisions. All those codes that checks if lines are intersecting seems too expensive for a game with many objects.

It depends on what your "many objects" look like : If none of the lines intersect you could simply find the nearest line-endpoint object, and check only the lines connected to it ...

Does anyone have a good example of drawing to a surface and make a mask of it?

You've allmost got it.

Create the surface once, in the create-event using "surface_create(...)".

Switch to drawing on the Surface :
surface_set_target(...)
draw_clear_alpha(...) //so the previous contents are erased

Drawing : Please notice that the upper-right of the Surface is at coordinate 0,0 (which, if you use a View, does not need to match what you are currently seeing on the screen !)

Stop drawing to the Surface :
surface_reset_target(...)

Thats about it. Between the setting of the Surface as the target and resetting it all draw-actions go to the Surface. Specifics can be found in GMs Help.

One remark : You cannot change the draw-target in the draw-event itself.

And you ofcourse need GM Pro for the above ...






Thank you! Currently in school, will test it out later and edit this post --
  • 0

#13 Pandaboy

Pandaboy

    GMC Member

  • GMC Member
  • 593 posts

Posted 29 October 2010 - 11:41 AM

I have a problem creating the sprite out of a surface.
- The surface is 250x250 pixels.
- I use the code below to make a sprite, with origin in middle:
global.spr_surface = sprite_create_from_surface(global.drawArea,0,0,250,250,true,false,125,125);

But somehow this copies the whole screen into a sprite, including the surface.
also.. I didn't manage to make drawing only happen on the surface. I tried setting the draw target in BeginStep and resetting the target in EndStep.




Edit:
Okay, so I searched for a surface tutorial, and found this one.
Teaches everything needed to know how to create and use a surface ^^.

Edited by Pandaboy, 29 October 2010 - 12:34 PM.

  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users