GMS 2.3+ I thought I had the hang of surfaces

I thought I had this down obviously not. I have the following code.

GML:
if !surface_exists(game_surface)
{
    game_surface = surface_create(1920, 1080);

    surface_set_target(game_surface);
    draw_clear_alpha(c_white, 1);

   draw_sprite(spr_bat, 0, 0); // NOT a problem
   instance_create_layer(0, 0, "lyr_gui", obj_bat); // PROBLEM

    surface_reset_target();
}

draw_surface(game_surface, 100, 100);
Why can I draw to the surface but when I create an instance the instance is on the application layer. This is my first time actual using an object with a pre-attached image on a non application surface.
 

Yal

🐧 *penguin noises*
GMC Elder
I thought I had this down obviously not. I have the following code.

GML:
if !surface_exists(game_surface)
{
    game_surface = surface_create(1920, 1080);

    surface_set_target(game_surface);
    draw_clear_alpha(c_white, 1);

   draw_sprite(spr_bat, 0, 0); // NOT a problem
   instance_create_layer(0, 0, "lyr_gui", obj_bat); // PROBLEM

    surface_reset_target();
}

draw_surface(game_surface, 100, 100);
Why can I draw to the surface but when I create an instance the instance is on the application layer. This is my first time actual using an object with a pre-attached image on a non application surface.
Surfaces are just blobs of raw texture memory, you can draw to them but you can't create entities on them.
 
I'm totally confused now. Let's say for argument sake My window is x1024, x1024 my surface is in the center of the window at that window at x512, x512.

I want an object to generate at the left-hand side of the 'window' (-256(surface)) and move to the right-hand side of the 'window' (+ 256(surface)).

The object is moving at a constant rate of 1 unit per second. My object has an image that is one pixel by one pixel.

I would expect to see the following:-

1) Second 1 - 255 (Nothing)
2) Second 256 - 768 (1 drawn pixel) (A pixel added as an object image, not a drawn one)
3) Second 769+ (Nothing)

I hope this example makes it clear where my miss understanding lies.

Edit: I guess then my question is how do you draw objects results to a surface. I can draw from an object to a surface. But What if I have an object that has an attached image that moves around via its in-built x and y variables. It'snot feeling like it's part of the surface at this point. I'm having a really hard time with this. Damn this is frustrating. 😤
 
Last edited:

Nidoking

Member
Are you confusing objects and instances with graphical data? Instances are entities within a game. They've got variables including position, speed, and default graphical data. But instances are not graphics. They draw graphical elements in their draw events. If you're drawing to a surface other than the application surface, then that's where the graphics go, but the instance doesn't actually exist as part of any collection of graphical data.
 
Thats what I thought. Forget surfaces beyond the default application surface then.

I have an object and it has an image attached to it via the IDE. If you create an instance of that object (The object has no code it's just a blank object with an image attached) it will display on the application surface.

If I create that object insde the surface 'encapsulation' code I was expecting my zero 'origin' to appear where the surface is offset from the application surface.

In answer to your question: Yes I must be totally mixing up instances and objects please help.

For further clarification:

1) An object can draw a line relative to it's the origin (object created at x, y)

2) When you draw in objects, draw code, that object causes drawing to happen. (This works on surfaces) I'm happy with that. (I'm pretty sure)

3) What is a blank object (An 'object' with no 'code') with an image /sprite attached to it, It does not seem to 'draw' it in the same way. It's not on the surface anymore.
 

Nidoking

Member
What is a blank object (An 'object' with no 'code') with an image /sprite attached to it, It does not seem to 'draw' it in the same way. It's not on the surface anymore.
If an object has no defined Draw event, it gets a default Draw event consisting of draw_self();. This is for convenience, so you don't have to define Draw events for every object unless you need something other than the default behavior. It should draw itself to the current target surface. However, since you won't know the order in which the various instances perform their Draw events, you'd have to do something like have an instance set the target surface in the Draw Begin event, then have everything draw to the surface, then reset the target surface and draw your surface in the Draw End event, if you want the instance to draw itself to the surface.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Moderator
If an object has no defined Draw event, it gets a default Draw event consisting of draw_self();. This is for convenience, so you don't have to define Draw events for every object unless you need something other than the default behavior. It should draw itself to the current target surface. However, since you won't know the order in which the various instances perform their Draw events, you'd have to do something like have an instance set the target surface in the Draw Begin event, then have everything draw to the surface, then reset the target surface and draw your surface in the Draw End event, if you want the instance to draw itself to the surface.
Or, alternatively, add a comment into the draw event of the instance so it WON'T draw, then draw it yourself to the surface... ;)
 

rytan451

Member
If an object has no code in it, then it has a very basic draw event:
GML:
if (sprite_exists(sprite_index)) draw_self();
If you want the instance to draw itself to a surface, then you need to set the surface target before the instance's draw event occurs (and also will need to reset the surface target some time afterwards). You can do this with layers, using layer_script_begin and layer_script_end and putting the instance on an appropriate layer. Or, you can override the draw event and set the surface target itself. However, calling surface_set_target before creating an instance does not magically prepend a call to surface_set_target to the instance's draw event; it simply doesn't work that way.

Your attempted clarifications do reveal a misconception, though. You said:

Let's say for argument sake My window is x1024, x1024 my surface is in the center of the window at that window at x512, x512.
A surface does not have a position. Saying that "My surface is at 512, 512" is like saying that "My bullet sprite is at 512, 512", when in fact there just only is one bullet object instance there. A surface is like a sprite: it can be drawn nowhere, or in many places. It is not "at" any one location.
 
I have one object let's say, and one image. That image is attached to that object in the 'IDE' named 'spr_test'. If I draw_self it means (in the draw event write draw_sprite(spr_test).

There are two very different results for this.

1) Blank object, image attached IDE. (Draws under surface) (Not part of surface)
2) Blank object, no image attached to IDE, in code draw_sprite... (Draws on the surface)

What I'm missing seems to be the function capabilities you get with the object itself. I can't do collision checks without using procedural code if I'm using draw_anything functions.

I can do a place meeting with something that is 'Drawn'.

I'm getting everything on both sides of the fence but I don't seem to be able to see the fence. Verging on tears
😢
 
I would really appreciate if I could put this one to bed. https://drive.google.com/file/d/1ZS8XMSPglib3ASqebi0hciBbWfPLlDql/view?usp=sharing

The link provided is a test project that you can just run. It will be immidiately obvious what the problem is. Hopefully.

1) one metod is an object drawing proceduaraly based of variables to draw to the surface.
2) the second is an object oreintated way I guess of doing this that dosen't seem to work.

If you look at the code (a dozen lines max) then run it. Things should be clear.
 

Nidoking

Member
1) Blank object, image attached IDE. (Draws under surface) (Not part of surface)
2) Blank object, no image attached to IDE, in code draw_sprite... (Draws on the surface)
GML collision functions and events operate on what WOULD be drawn if you used the draw_self function. That takes into account sprite_index, image_index, image_[x/y]scale, etc. Those define the bounding box for the instance, which feeds into the _meeting and instance_ functions. If you want to use those functions, you must assign appropriate sprites and positions to every instance. However, if you override the default Draw event and you don't draw the sprite to the application surface in the overridden event, then it doesn't get drawn to the application surface. You could, instead, draw the sprite or whatever you want to a different surface. Whatever it is you're doing to draw the sprite to the surface in your case 2, you do that in the object's Draw event, and you don't do a draw_self. Then you have "image attached IDE", as I think you intend it to mean, because the object and instance have a defined sprite to be used for collisions. But that's going to determine collision based on where the instance is located in the room, not where the sprite is drawn on the surface or where the surface is drawn in the room. So, if you're doing something to ensure that the position where the sprite on the surface is drawn matches where the instance thinks the sprite is located, that should do what you seem to want.

In other words, yes, if you overwrite the standard draw, then the drawing becomes independent of the other mechanisms in the program. You need to handle that if you want to use those mechanisms. It can be done, but you have to understand the mechanisms to do it properly.
 
What I'm missing seems to be the function capabilities you get with the object itself. I can't do collision checks without using procedural code if I'm using draw_anything functions.

I can do a place meeting with something that is 'Drawn'.
No, you cannot do place_meeting() with something that is "drawn". At least, not in the context that you are thinking of. All collision functions of any type, even custom ones, exist completely independent of what is actually drawn to the screen (though some of the variables that the drawing ALSO uses might be relevant to the collision functions). All drawing does is put some pixels on a screen. A collision function does not look at those pixels. However, instances store data about where they "are" in game space. This "where" can be related to where they are drawn, but it can also be totally unrelated. This is why you can do things like check for a collision, move an instance, check for another collision, move an instance and so on multiple times in the same step. If the collision had anything to do with where things were being drawn, then that sort of code would be impossible, you'd have to wait for the next step.

I mean, once again, I think you are overcomplicating things in your head. Collision functions work around the x and y positional data stored in an instance. Drawing something is simply drawing something. It is not intrinsically linked to anything really. It's just a drawing. If you are drawing something in an instance at a position that has no relation to the x and y of that instance, then yes, you will have to check for collisions yourself, using the coordinates of where you are drawing the thing, instead of using x and y.
 
This is what I have been doing. I understand that if it is drawn it can't know where it is unless you do it all manually, which I have. point_in_rectangle(var_x, var_y, etc).

If you look at the test example link provided above. It would make much more sense.

1) I have one object that has an 'image attached IDE' that draws all the time based on an ever-changing variable which makes it appear as though it's rotating. (The way my brain works)

2) The same thing except the image is attached to the object and is rotating by image_angle ++.

The difference is the first example sits on the surface and the other just doesn't give a damn. The only thing that will hide that is if it's (outside the window) or it's invisible or on a higher layer.

It would make a lot more sense if you see the example.

https://drive.google.com/file/d/1ZS8XMSPglib3ASqebi0hciBbWfPLlDql/view?usp=sharing

I'm very condufed by this 'draw_self()' Does this mean draw the images thats attached to the object. 'Draw_self()'. It confuses me.
 
Last edited:

Nidoking

Member
draw_self is basically just a draw_sprite_ext call using the instance's variables for the parameters. If you look at the example at the bottom of this Manual page, it pretty explicitly tells you what draw_self does.
 
I can still use collisions as long as I know where the x, y, and width, height of the drawn objects are without any panic. Is that correct? (Meaning I understand I'm not checking pixels per se)

I did everything procedurally before. I was multiplying sprite widths by its scale to get it's 'actual width'. Nasty things like that.

Then I find if you attached a sprite to an object and you ask for its the width and then do an in-built, sprite_width it does that quote-un-quote (nasty) calculation for you. (Which is what I thought the whole point was)

But now we are talking about surfaces. It seems that I need to draw it again. (The 'nasty way').
 
Figuring out the width by multiplying the sprite width by the scale isn't nasty, it's how both you and GMS does it under the hood. Though, it's better to use an instance variable and only update it when the scale is changed, rather than calculating every step. But it's not a "nasty" way of doing it.
 
When I said 'nasty' I did mean under the hood. But it was more to do with people are saying don't do stuff procedurally because it does a wonderful job for you.

That's great. That's why I use it.

I want to use the tools available I really do. I just don't understand if I'm using them 'correctly' is basically what it comes down to.

So does a bitmask follow the x / y of the object by default, regardless of the mask itself?

This is why you can't draw and attach a sprite at the same time?

I was always worried that by drawing things using a draw_anything command I was undoing any possible physics, collision, or any other special functions that would ever make GMS useful.

You guys are saying that I can draw something to the screen with a draw function and still make use of Gamemaker without writing everything out by hand.

I'm not trying to insult anyone honestly. Sorry refresher towel :confused:
 
Last edited:

rytan451

Member
Yes, you can draw something to the screen with a draw function and make use of GMS's other features. It is something that I commonly do: I sometimes make my objects draw their bounding boxes in a transparent color for debugging purposes. Because it's just drawing.

You can pretend that the game has two things going on. First, there's the collision masks (imagine those as a bunch of faceless rectangles) that are determined by the object instances' masks, rotations, positions, and scales. Second, there's what's actually being drawn, which can be completely different but is usually very similar. If you imagine the collision masks as a blueprint and what's being drawn as a building, then adding graffiti to the building doesn't change anything about the blueprint.
 

Rob

Member
You could add all the instances to a queue that you want to be drawn on a surface (1 queue per surface??), change the surface to your target surface, draw the contents of the queue, and then reset the surface.

I haven't used surfaces a lot but I'm pretty sure this will work.
 
You're not being insulting, lol.
You guys are saying that I can draw something to the screen with a draw function and still make use of Gamemaker without writing everything out by hand.
So, we're kinda saying the opposite. There're two cases where you can just use the inbuilt collision events/mask.

1. You're using draw_self()
2. You're using this (in particular the arguments I've added * to): draw_sprite_ext(sprite_index*,image_index,x*,y*,image_xscale*,image_yscale*,image_angle*,image_blend,image_alpha)

If you do anything besides those, you're probably going to have to handle collisions and stuff yourself (although, it depends, like most things). Drawing something at a different position to x and y means that you'll have to calculate a collision at the new x and y coordinates yourself. Rotating or scaling the sprite seperately from image_xscale, etc, and image_angle, means you'll have to calculate the altered collision yourself (if it matters, for instance, often times people simply use a non-rotated square for collision regardless of what rotation the actual sprite has). If you don't use sprite_index, you'll have to account for the size of the different sprite you are using.

Basically, the inbuilt events are designed for use with draw_self(). Once you start drawing different things, you'll have to start working with the collision functions, not the events, and this often means supplying the "new" data to the collision function so that it accords with whatever you are drawing.

As a sidenote: Doing this kind of thing is necessary and totally ok. There's nothing wrong with using events when it's valid and using collision functions seperately when it's valid. Trying only to stick to one or the other is going to introduce unnecessary workarounds in some scenarios. Use all the tools you've been given by GMS when those tools are the best for the situation. And, as I've said before, a finished project that's not perfectly coded is worth infinitely more than an "eternally being worked on" project that is perfectly coded but will never be finished. The best game studios in the world end up using hacks by the end of their production schedule because it's almost impossible to anticipate every possible scenario and variation that can arise when you are just starting on a project, and constantly going back and rewriting code quickly becomes not worth the time, depending on how often you are doing it.

Give yourself a schedule and stick to it. If you find you are spending all of the allocated time trying to perfect code and you can't complete the project within the schedule, make a note of that fact and alter where you are aiming your efforts. Time and effort (and life) is a limited resource. Spend it wisely to bring your projects to life while you can.
 

ThraxxMedia

Member
Maybe a little bit off-topic, but hopefully it'll give the OP a better understanding of the difference between instance handling and drawing:

Imagine for a moment that your game project is one of these grappling arm machines at a fairground. The whole thing represents your game and what it's doing.

The person operating the machine might be the player, doing their inputs. Now, in terms of instances - look at an instance like you look at the grappling arm. You control it, you can move it around and set its position, you can make it go up and down... but it doesn't have anything in it (and for the sake of the arm simply existing, it never needs to). ONLY whenever you specifically tell it to pick up a toy is when you get a visual result. You can't modify that result in the same way you did with the instance once you've got it though; you can only modify the position of the arm, not the position of the toy itself.

The toy would be the sprite that's drawn to the screen. You can't directly control it; it's at the mercy of the arm (i.e. instance) "carrying" it. But if you pick it up (i.e. draw it), you can see it's there.

Now of course, you may always draw sprites with an offset, for example... technically assuming "control" over their position.
But where would you write the piece of code that does this? Exactly: within a controlling instance. The basics of what I explained above remain unchanged.

Hope that made at least the tiniest lick of sense. 😅
 
Last edited:
This is somewhat clearer. I do spend way too long trying to make things perfect and re-writing already re-written code. It's painful. I just don't want to find out I have fundamentally misunderstood something halfway through a project.

Is it common for people to place a surface the size of the window just as a matter of course for a new project?

Thanks, guys

Edit: Would someone be able to post a very simple example. I find it a lot easier if I have something to look at. I just want to see two objects colliding together on a surface. That's all I want to see. I don't know how to do it without having the image attached.
 
Last edited:
Top