Legacy GM How to Draw a Clipped Sprite , pseduo3D

Hello all. I'm currently converting a JavaScript Pseudo3D racing game. So far i've gotten everything to work fairly well however, i've run into a huge problem. I'm trying to clip a sprite based on the cameraY, if a Hill is blocking the way or if it's not in view, to draw only part of it, or none at all


The tutorial I'm following uses the JS function
Code:
drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
which looks very similar to draw_sprite_part. The only major difference is the last 2 parameters, which is what i need to set the width and height so the image looks like its appearing smaller when farther away. If i use
Code:
draw_sprite_stretched()
It seems to work, and the only thing missing is the clipping I'm really at a loss here for what to do. Is there a function for draw_sprite_part with width and height paramaters ?
 

Binsk

Member
Use primitives and build a rectangle the size you want (out of two triangles) with the texture offset as you'd like then draw that instead of using draw_sprite.

Alternatively you could use draw_sprite_general or whatever and submit a custom matrix before drawing it to do the scaling separately.
 
Use primitives and build a rectangle the size you want (out of two triangles) with the texture offset as you'd like then draw that instead of using draw_sprite.

Alternatively you could use draw_sprite_general or whatever and submit a custom matrix before drawing it to do the scaling separately.
This sounds interesting, I understand the basic of what you're telling me to do , basically create a rectangle using something like pr_trianglelist that makes up the size of the width and Height of the sprite itself.
However i'm having a bit of a hard time understanding how that would help to draw only part of the sprite when theres a hill blocking, or full when its in plain view.
 

Binsk

Member
Oh, if that's all that's happening then set the sprite on a depth lower than the hill? It will be drawn first and the hill will be drawn on top. You can change the depth of any object through code (doesn't work mid-draw, though. Takes a step to update)

If you can't do this then explain why and we'll try to figure something else out.
 
D

Danei

Guest
Yes i've tried that too the problem with draw_sprite_general is still the same as draw_sprite_part_ext
there's no width and height arguments to draw the image's with a specific width and height amount
Can't you use the xscale and yscale arguments for that?
 
D

Danei

Guest
Those values get over written when drawing manually unless using draw_self, I believe.
I'm talking about the argument in the draw functions, e.g. draw_sprite_general(sprite, subimg, left, top, width, height, x, y, xscale, yscale, rot, c1, c2, c3, c4, alpha), not the variables.
 

Binsk

Member
I'm talking about the argument in the draw functions, e.g. draw_sprite_general(sprite, subimg, left, top, width, height, x, y, xscale, yscale, rot, c1, c2, c3, c4, alpha), not the variables.
Oooh, good idea. Didn't have the manual up so I didn't know all what arguments it supported.

Yeah, if you know the original size of the sprite and the size that you want it just takes some basic algebra to figure out how much to scale it by.

Edit: This phone's spell check will be the end of my sanity. Gracious...
 
T

Taddio

Guest
Pretty sure that
Code:
var _scale, _dist;
 _dist = //how far your mountain is
_scale = _dist*SOME_FACTOR
you could put _scale as your x/y scale and it would work ok.
Good chances SOME_FACTOR wont look good if it's somewhat linear, but I'm not an expert on how perception translates in maths, sorry!
 
Oh, if that's all that's happening then set the sprite on a depth lower than the hill? It will be drawn first and the hill will be drawn on top. You can change the depth of any object through code (doesn't work mid-draw, though. Takes a step to update)

If you can't do this then explain why and we'll try to figure something else out.
This will not work because the Hills are drawn first. All of my roads are Projected in segments and are drawn first. then the second loop renders the Sprites that are meant to be on the track.

I'm talking about the argument in the draw functions, e.g. draw_sprite_general(sprite, subimg, left, top, width, height, x, y, xscale, yscale, rot, c1, c2, c3, c4, alpha), not the variables.
Pretty sure that
Code:
var _scale, _dist;
 _dist = //how far your mountain is
_scale = _dist*SOME_FACTOR
you could put _scale as your x/y scale and it would work ok.
Good chances SOME_FACTOR wont look good if it's somewhat linear, but I'm not an expert on how perception translates in maths, sorry!
Funny enough I somewhat ended up doing that. I've made some progress and it seems to work decently well, however there is still a problem. For the tutorial I am following the width and Height are calculated based on the cameras Y position so it tells the game how much of it to draw. so what i ended up doing is calculating the scale factor.
x_scale = NewWidth/sprite_get_Width(sprite) which gives me a decimal or a percentage of the scaling which is what i used.

This is how my current code looks like.

Code:
var sw=sprite_get_width(sprite)
var sh=sprite_get_height(sprite)

var s_scale=(1/sprite_get_width(sprite))
                 //  scale for projection AND relative to roadWidth
    var destW  = (sprite_get_width(sprite) * scale * width/2) * (s_scale * roadWidth);
    var destH  = (sprite_get_height(sprite) * scale * width/2) * (s_scale * roadWidth);

    destX = destX + (destW * (offsetX));
    destY = destY + (destH * (offsetY));

    var clipH = clipY ? max ( 0,destY+destH-clipY ): 0;
   
    if (clipH < destH)
    {
    draw_sprite_part_ext(sprite,index,0,0,sw,sh-(sh*clipH/destH),destX,destY,destW/sw,(destH+clipH)/sh,c_white,1)   
    }
While this somewhat works out well theres still a bit of a problem with some of the sprites clipping through and i think it's due to how Gamemaker draws up the sprites.
Currently it's a 2 Step process.

1. Project the Road Segments
2. Project Player and other sprites that need to be drawn.

As you can see, it seems to be working but when the Trees start going down the hill you can see a part of it where you're not supposed to.

upload_2019-4-10_16-6-10.png
 
Last edited:

Binsk

Member
Hum... May not be the best in terms of optimization, but could you also render the road and whatnot to a surface as a mask and then use that mask to cut out pieces of the trees as they are drawn?

This would require blend modes, some extra rendering, and of course surfaces, but of would allow hiding pieces of sprites behind the road.
 
T

Taddio

Guest
This will not work because the Hills are drawn first. All of my roads are Projected in segments and are drawn first. then the second loop renders the Sprites that are meant to be on the track.





Funny enough I somewhat ended up doing that. I've made some progress and it seems to work decently well, however there is still a problem. For the tutorial I am following the width and Height are calculated based on the cameras Y position so it tells the game how much of it to draw. so what i ended up doing is calculating the scale factor.
x_scale = NewWidth/sprite_get_Width(sprite) which gives me a decimal or a percentage of the scaling which is what i used.

This is how my current code looks like.

Code:
var sw=sprite_get_width(sprite)
var sh=sprite_get_height(sprite)

var s_scale=(1/sprite_get_width(sprite))
                 //  scale for projection AND relative to roadWidth
    var destW  = (sprite_get_width(sprite) * scale * width/2) * (s_scale * roadWidth);
    var destH  = (sprite_get_height(sprite) * scale * width/2) * (s_scale * roadWidth);

    destX = destX + (destW * (offsetX));
    destY = destY + (destH * (offsetY));

    var clipH = clipY ? max ( 0,destY+destH-clipY ): 0;
   
    if (clipH < destH)
    {
    draw_sprite_part_ext(sprite,index,0,0,sw,sh-(sh*clipH/destH),destX,destY,destW/sw,(destH+clipH)/sh,c_white,1)  
    }

While this somewhat works out well theres still a bit of a problem with some of the sprites clipping through and i think it's due to how Gamemaker draws up the sprites.
Currently it's a 2 Step process.

1. Project the Road Segments
2. Project Player and other sprites that need to be drawn.

As you can see, it seems to be working but when the Trees start going down the hill you can see a part of it where you're not supposed to.

View attachment 24167
Looks pretty good, seems like it's only a tree or two that are glitched a little. Maybe spreading them out a little bit more could hack it, somehow (less chance of being a tree in the glitch area), or go the long a road and maybe draw another layer altogether, something like (from furthest to closest)
- sky
-mountains
-trees
-Far road ***this is your new layer***
-Near road
-Car and GUI

The principle of Far Road layer is to draw what's beyond the top of the nearest hill if the hill after that goes higher, like in your example. That is a whole extra layer of work as well, personally, I think I'd try to do it in a hacky way that looks fine. You're already close, tho!
 
Looks pretty good, seems like it's only a tree or two that are glitched a little. Maybe spreading them out a little bit more could hack it, somehow (less chance of being a tree in the glitch area), or go the long a road and maybe draw another layer altogether, something like (from furthest to closest)
- sky
-mountains
-trees
-Far road ***this is your new layer***
-Near road
-Car and GUI

The principle of Far Road layer is to draw what's beyond the top of the nearest hill if the hill after that goes higher, like in your example. That is a whole extra layer of work as well, personally, I think I'd try to do it in a hacky way that looks fine. You're already close, tho!
See I didn't want to do that in case i wanted to add more stuff there, however i come back with great news, i seemed to have solved it. :D!

upload_2019-4-10_21-58-38.png
 
Looks great! More spreaded out like that looks more natural
Thanks man I totally agree it looks alot more natural, i might even just spruce it up a bit by making random trees appear throughout the road-sides!

I appreciate the help and to everyone else too, I might release it later on as a tutorial myself, or an asset on the marketplace, so no one will have to suffer as much as i have converting this :') or have a clear idea how to do it themselves later on.
 
Top