Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird Double Drawing Of PlayerObject Ontop Of Everything #74

Open
FluffyDuckyEU opened this issue Feb 18, 2023 · 22 comments
Open

Weird Double Drawing Of PlayerObject Ontop Of Everything #74

FluffyDuckyEU opened this issue Feb 18, 2023 · 22 comments
Labels
bug Something isn't working

Comments

@FluffyDuckyEU
Copy link
Contributor

I don't understand this line, it seems like a hack and it is having an impact on the wing effects.

https://github.com/Suprcode/mir3-zircon/blob/3a890d540ed4fa4a9b90f0089d2c3cadf2ef05e4/Client/Scenes/Views/MapControl.cs#L405

Removing it has a consequence, so it's not so simple, i assume this is the reason this was added.

  • Player does not implicitly show when hiding under objects (without mouse over).
  • We lose the colour overlay when hiding under objects (this behaviour could be moved elsewhere though?).

With This Line
UnnecessaryDraw

Without This Line
UnnecessaryDraw2

@FluffyDuckyEU
Copy link
Contributor Author

FluffyDuckyEU commented Feb 18, 2023

I feel like this should be handled as part of PlayerObject Draw() method.

https://github.com/Suprcode/mir3-zircon/blob/3a890d540ed4fa4a9b90f0089d2c3cadf2ef05e4/Client/Models/PlayerObject.cs#L801

Imo maybe I should just reimplement that whole Draw method while i'm touching it :|

@Suprcode
Copy link
Owner

Suprcode commented Feb 18, 2023

Yes double drawing has always been a requirement to see yourself behind objects.

I don't think you lose the colour when you hover if that's what you meant. Just a side effect of the draw blend / opacity making the image brighter and losing colour I think.

I'm not sure how you'd plan to get around needing to double draw. The simplest fix would be to just double draw the wings too - I can't think of any other way you can resolve it in a single draw.

@FluffyDuckyEU
Copy link
Contributor Author

It seems like a waste to process twice, i was hoping to be able to determine whether the character is hidden whilst processing in the PlayerObject.Draw but because the map object spans over multiple cells whilst only actually being assigned to one cell that the player isn't likely on makes it not possible like you said :/

@Suprcode
Copy link
Owner

To be honest you probably can work it out. You'd have to look at the current X coord, and all Y coordinates directly below the player (plus maybe +/- 1 X due to overflowing image to out cells). Then you'd need to look at all 3 layer images to see if the cell height reaches the player.

It'll certainly be an expensive calculation to constantly do, so you'd need to ensure its cached - which might use abit of memory after a certain period.

@Suprcode
Copy link
Owner

Suprcode commented Feb 19, 2023

Thinking about it, you're really only going to need to calculate 3 cells below you - each time you move. So maybe not that expensive and worth looking in to. Certainly would be better than drawing opacity over the player constantly

@FluffyDuckyEU
Copy link
Contributor Author

I thought some map objects were quite tall, let me see if I can investigate that as a separate thing.

@Suprcode
Copy link
Owner

Suprcode commented Feb 19, 2023

They are, but there's only 3 cells below you. Any objects lower than that won't get drawn, even if they're more than 3 cells tall. I think.

@FluffyDuckyEU
Copy link
Contributor Author

Here is the same example. This particular object is 1x13 size.

image

@FluffyDuckyEU
Copy link
Contributor Author

FluffyDuckyEU commented Feb 19, 2023

Do you think it's still possible to be able to calculate a top image that is up to maybe 10 cells away from your character?

Sorry for the horrible pink lines, i don't know where i found this program but it does the job for viewing the map😅

image

@FluffyDuckyEU
Copy link
Contributor Author

FluffyDuckyEU commented Feb 19, 2023

The more I think about it, the more I think it's not possible, how would you also handle a character half under shelter and half not? The double draw handles this, but would you end up with the draw fully oqaue not opaque at all if you had this situation with manually worked out solution?

image

@Suprcode
Copy link
Owner

You'd have to just double draw as soon as the feet/player cell is in the area. But it still means 99% of the time you're not double drawing.

Maybe write the function to search for 10 coords below you and see how the performance is. Since you only need to do it once every time you move, it'll probably be fine

@FluffyDuckyEU
Copy link
Contributor Author

I may be thinking about this too simply, but using the cell positions I don't think is enough to work.

image

Maybe you have something in mind that i don't, when you say:

Then you'd need to look at all 3 layer images to see if the cell height reaches the player.

How would I know if the map object image overflow lands on top of the player fully or not? The only way I can see this being achieved is if you check whether the images intersect, not by cells but by pixel maybe?

@Suprcode
Copy link
Owner

Suprcode commented Feb 19, 2023

The images only ever go as high as they have atleast 1 pixel in them. As you can see from below the pink cells show the bottom of each image (where its physically placed).

image

So all you need to do is get the height of the image, divide is by the constant cell height - that'll give you the cells tall an image is.

then as you loop down your Y coord - you check if the player coord is greater than the Y coord minus the image height. If it is, you know the player is over it.

player Y = 100

checking Y coord = 105
105's image height = 5

if (100 > 105 - 5) Player is behind image.

image height will always be minimum of 1. So in most cases for a single cell image

if (100 > 101 - 1) player not behind

(you'll need to do this on front and middle layers)

Should be as simple as that. Obviously you're not going to be able to know if just a foot is behind the image, but you're still massively reducing when you have to double draw the player.

@Suprcode
Copy link
Owner

I've given this a quick go, and although it does kind of work - it certainly not perfect.

public bool IsBehindObject()
        {
            if (User == null) return false;

            var location = User.CurrentLocation;

            IsBehind = false;

            for (int offset = 0; offset < 20; offset++)
            {
                var y = location.Y + offset;

                var cell = Cells[location.X, y];

                if (cell == null) continue;

                LibraryFile file;
                MirLibrary library;

                if (Libraries.KROrder.TryGetValue(cell.MiddleFile, out file) && file != LibraryFile.Tilesc && CEnvir.LibraryList.TryGetValue(file, out library))
                {
                    int index = cell.MiddleImage - 1;

                    Size s = library.GetSize(index);

                    var cellsTall = s.Height / CellHeight;

                    if (location.Y > (location.Y + offset - cellsTall))
                    {
                        IsBehind = true;
                        break;
                    }
                }

                if (Libraries.KROrder.TryGetValue(cell.FrontFile, out file) && file != LibraryFile.Tilesc && CEnvir.LibraryList.TryGetValue(file, out library))
                {
                    int index = cell.FrontImage - 1;

                    Size s = library.GetSize(index);

                    var cellsTall = s.Height / CellHeight;

                    if (location.Y > (location.Y + offset - cellsTall))
                    {
                        IsBehind = true;
                        break;
                    }
                }
            }

            System.Diagnostics.Debug.WriteLine(IsBehind ? "true" : "false");

            return IsBehind;
        }

Then add an "IsBehind" variable to map control

call this line inside LocationChanged()

GameScene.Game.MapControl.IsBehindObject();

and finally wrap drawPlayer around the check


if (IsBehind)
            {
                MapObject.User.DrawPlayer(false);
            }

It would probably be much better just doing this check when the map gets drawn itself - and it doesn't always look to work, often i find myself double drawing when i'm not behind anything.

Ideally checking if there is a visible pixel on the image would be much better - but i can only think performance on that would be an issue.

@FluffyDuckyEU
Copy link
Contributor Author

I didn't have much time to look myself but i was thinking more along this train of thought, but it didn't work.. maybe i missed something simple.

image

@FluffyDuckyEU
Copy link
Contributor Author

FluffyDuckyEU commented Feb 20, 2023

Ah it does kind of work if I change this code a bit.

                        if (!playerOverlap)
                        {
                            if (s.Width == 0 || s.Height == 0) continue;

                            Rectangle MidImage = new Rectangle(drawX, drawY, s.Width, s.Height);
                            bool result = !Rectangle.Intersect(MidImage, playerRectangle).IsEmpty;
                            playerOverlap = result;
                        }

It still has issues though.

  • Flickering when transitioning between cells
  • Not drawing if the head is showing, weirdly it works if the head is hidden and bottom half of body is showing.

DDB

Maybe easier to see without the huge armour wings.
DDB1

@Suprcode
Copy link
Owner

That sounds like a much better approach

i think you'll need to cache it though so it only rechecks once per player move.

Also, the player dimensions are alot more than just body - if you look in DrawBody theres an l/t/r/b value which gets used to create the shadows - maybe you can store this as a rectangle to reuse it for intersecting?

@Suprcode Suprcode added the bug Something isn't working label Mar 17, 2024
@josh-74
Copy link

josh-74 commented Sep 4, 2024

I've done some work on this and I've made the player's Opacity to = 0F; when it's detected behind an object, even with mouse hover it's completely invisible, although Objects of other types are visible upon mouse hover which can be fixed...
Not sure what FluffyDuckEU was completely wanting though?

Edit; if it's the wings which are causing this effect, then id need item name so i can check too... can't find anything in the database regarding wings which can be equipped.

0a9048eeb44e89f6977070c3163a82e9.mp4

@Suprcode
Copy link
Owner

Suprcode commented Sep 4, 2024

It wants to be the opposite of that. It should only draw once when you're not behind an object - and draw twice when you are (as you should see yourself transparently when behind objects).

Currently it draws twice all the time, which is the issue needing to be resolved.

@josh-74
Copy link

josh-74 commented Sep 4, 2024

Interesting, if the areas on the map where this is happening can be pinpointed that'd be great, on my end it's not appearing for me at all, my character consistently stays at half opacity when under any roofs or big entrances.

I've also ensured the code draws the player if the opacity condition is met, which also feels 100x more smoother now when running under any roof tops.

@Suprcode
Copy link
Owner

Suprcode commented Sep 4, 2024

the issue isn't when behind an object, its all the other time when you're not.

the player is being drawn twice, all the time. Once at full opacity, and once at half opacity.

The half opacity drawing should only be done when stood behind an object. If not, it should not be drawing the opacity body at all.

@josh-74
Copy link

josh-74 commented Sep 5, 2024

It's been an interesting journey tbf, it's so sophisticated in rejecting the 30 different methods that it could use in-order to reject the double drawing that it simply does not accept it, more or less needs a complete draw system remap it seems. Way beyond my expertise personally, I've previously formulated code in which it should've taken as a switch method to stop scanning the Opacity constantly all the time. And to switch to the other Opacity when it needed to, to create a single drawing method. But with this it would end up switching off the second draw method completely, and wouldn't detect correctly when it needed to do so.
I'll defiantly keep coming back to this but it's defiantly been interesting.

The UI for MonsterBox also needs working on, with my files I've made MapControl.cs & GameScene.cs talk to each other, implemented individually where it's been needed in-order to stop displaying the MonsterBox on case MouseButtons.Right:
which after some fixes this was what was all left in-order to completely fix it
As the Click functions solves this via MapControl & GameScene it appears, as far as I've gotten with fixing the box is by removing the UI when the mouse isn't hovering over mobs, (before it was). But even after the debugging and implementing and no errors appearing, it still refuses to output the code, defiantly something I'm not doing right, but a lot more studying C# and these files on my end that's for sure.
(although on any future commits if so, I'll ensure it's done properly, but in regards to getting the files to talk to each other was just a reference to see if I could fix it in-between those two).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants