Jump to content

Recommended Posts

  • Active+ Member

This is the hidden content, please

Hello! I was in my learning process of how the UI things from Login are working and I did this mini-MOTD section. 

Features

  • Here, multiple images can be displayed depending of how many you set. 
  • These images are automatically changed after 3 seconds (you can easily change that)
  • Maybe it has potential for an "Ad spot" from different services. 
  • You can assign links for these images. Clickin' on them you'll be redirected in your default browser (only 3 links were added - for the 1st 3 images)

Bugs and things "to know"

It has only one bug, and that is the thinboard title that appear empty in the Server selection. I don't know how to fix that yet. If you find any other bugs, please let me know. I'll post them here or if I can, I'll fix them. 

Also, please keep in mind that the images are 474 x 314 as size. I've made the thinboard based of the 1st image I've found on google. You can change your layout / dimensions from the loginwindow.py. 

 

What I want to add

  • I want to add a slide effect or fade effect for images when are changed BUT I couldn't figure it out how to do it. I've tried a lost of things, but I haven't found any solution to this. (If anyone can do this please SAVE ME!)
  • Some social media / Additional buttons in the adtitle thinboard. 

If you have any other ideas please let me know!!

 

PREVIEW: 

https://metin2.download/picture/Ykru5R0wB3zEovf1ldsZGpLCTP0WxfxQ/.gif - The gif it looks weird due to the Loop, but the images are changed at an equal time. 

https://metin2.download/picture/L6syIG1qxwQLVFvt8y605FBram044H9C/.gif

 

 

If you are interested in this PLEASE let me know! I'll be happy to see final preview of this! 🙂 

  • Metin2 Dev 19
  • Good 1
  • Love 1
  • Love 1
Link to comment
https://metin2.dev/topic/33006-login-motd-whats-new-section-or-an-ad-spot/
Share on other sites

  • Premium
On 9/19/2024 at 6:38 PM, KolenMG said:


What I want to add

  • I want to add a slide effect or fade effect for images when are changed BUT I couldn't figure it out how to do it. I've tried a lost of things, but I haven't found any solution to this. (If anyone can do this please SAVE ME!)

What I would do is keep rendering the current image, then render on top of it the next image with 0 alpha and then increase that alpha over time. You can do it in the OnUpdate depending on the time elapsed. If you want something fancy you can even use some tweening so it wont be completely linear. Probably that would look the best. Maybe do that animation under 500 millisec or less. You can set the image alpha with SetDiffuseColor keeping it rgb 1.0 and alpha as mentioned before. (Maybe there is even a function called SetAlpha on ImageBox objects.) Also you can force disable the next/prev button while the animation is running so they cant spam it cus that would look kinda bad, can make it work anyway but probably would take much effort to figure a mechanic out for those cases. And if a button is disabled for like half a second noone would be annoyed about that. Probably thats how it works on webpages and whatnot.

You can make other kind of animations as well like sliding left/right, you can do that as well without extra code in the binary using SetRenderingRect like how it works on gauges like the HP bar. So basically you change the visible part on the top image to be even less while moving its position to the left/ right depending on which button you click on.

Either way you are going to need some interpolation in the OnUpdate method based on time.

def UpdateMoving(self):
	maxH = self.peekBoard.GetHeight()
	if self.isOpen:
		hGoal = maxH
	else:
		hGoal = 0

	currH = self.GetHeight() - self.peekBoard.GetLocalPosition()[1]
	normalRate = min(1.0, float(app.GetChronoClock() - self.progressStart) / self.ANIM_TIME)
	if currH != hGoal or normalRate < 1.0:
		me = self
		if type(me) != weakref.ProxyType:
			me = proxy(self)

		rate = self.ANIM_FUNC(normalRate)
		if not self.isOpen:
			rate = 1.0 - rate
		newGoal = round(maxH * rate)

		change = newGoal - currH

		if change:
			self.SetSize(self.GetWidth(), self.GetHeight() + change)
			self.owner.peekBoard.NotifySizeChange(me, change, keepScrollPos = True)
		self.arrow.SetRotation(-90.0 + rate * 90.0)

Here is an example from one of my UI where you can click on an image which would slide open/close up like a spoiler tag. You can use the GetGlobalTime or whatever its name from app. instead of my GetChronoClock to get the time right. The ANIM_TIME is set in milliseconds that tells how much time you want to spend on the animation (like it should complete under 500 milliseconds). The ANIM_FUNC is just a function from the mentioned pyTweening library. Rate is obviously something between 0.0 and 1.0. The isOpen tells me if I'm opening the board or closing it. As you can see I also have an arrow image which is getting rotated alongside the opening animation. The change variable tells me how much should I enlarge the opening/closing board on that animation cycle. This whole function is just called on each OnUpdate. The goal is either 0 or the maximum possible height of that board. The currH is obviously the current height - the header's height because I don't want to close the entire window because otherwise you can't open it anymore as you won't see the header and can't click on again duh 😄

Oh almost forget, you start the animation by changing self.isOpen + setting the current time to self.progressStart. The reason why I have a separate self.progressStart is because if the window is not open or not shown, the OnUpdate won't be called, and the animation would stop and only resume when you open it again. Also you can force skip an animation this way if you set the self.progressStart to a time earlier than current time - self.ANIM_TIME (or just simply set it to 0), which would make the animation complete in the next OnUpdate call. Probably not needed in you case, just good to know.

So yeah there you go thats pretty much it, you can apply it to any kind of animation, you just need a minimum value to go from and a maximum value to go to, and multiply the maximum value with the rate.

Edited by masodikbela
  • Love 1

The one and only UI programming guideline

  • Active+ Member
On 9/21/2024 at 3:19 AM, masodikbela said:

What I would do is keep rendering the current image, then render on top of it the next image with 0 alpha and then increase that alpha over time. You can do it in the OnUpdate depending on the time elapsed. If you want something fancy you can even use some tweening so it wont be completely linear. Probably that would look the best. Maybe do that animation under 500 millisec or less. You can set the image alpha with SetDiffuseColor keeping it rgb 1.0 and alpha as mentioned before. (Maybe there is even a function called SetAlpha on ImageBox objects.) Also you can force disable the next/prev button while the animation is running so they cant spam it cus that would look kinda bad, can make it work anyway but probably would take much effort to figure a mechanic out for those cases. And if a button is disabled for like half a second noone would be annoyed about that. Probably thats how it works on webpages and whatnot.

You can make other kind of animations as well like sliding left/right, you can do that as well without extra code in the binary using SetRenderingRect like how it works on gauges like the HP bar. So basically you change the visible part on the top image to be even less while moving its position to the left/ right depending on which button you click on.

Either way you are going to need some interpolation in the OnUpdate method based on time.

def UpdateMoving(self):
	maxH = self.peekBoard.GetHeight()
	if self.isOpen:
		hGoal = maxH
	else:
		hGoal = 0

	currH = self.GetHeight() - self.peekBoard.GetLocalPosition()[1]
	normalRate = min(1.0, float(app.GetChronoClock() - self.progressStart) / self.ANIM_TIME)
	if currH != hGoal or normalRate < 1.0:
		me = self
		if type(me) != weakref.ProxyType:
			me = proxy(self)

		rate = self.ANIM_FUNC(normalRate)
		if not self.isOpen:
			rate = 1.0 - rate
		newGoal = round(maxH * rate)

		change = newGoal - currH

		if change:
			self.SetSize(self.GetWidth(), self.GetHeight() + change)
			self.owner.peekBoard.NotifySizeChange(me, change, keepScrollPos = True)
		self.arrow.SetRotation(-90.0 + rate * 90.0)

Here is an example from one of my UI where you can click on an image which would slide open/close up like a spoiler tag. You can use the GetGlobalTime or whatever its name from app. instead of my GetChronoClock to get the time right. The ANIM_TIME is set in milliseconds that tells how much time you want to spend on the animation (like it should complete under 500 milliseconds). The ANIM_FUNC is just a function from the mentioned pyTweening library. Rate is obviously something between 0.0 and 1.0. The isOpen tells me if I'm opening the board or closing it. As you can see I also have an arrow image which is getting rotated alongside the opening animation. The change variable tells me how much should I enlarge the opening/closing board on that animation cycle. This whole function is just called on each OnUpdate. The goal is either 0 or the maximum possible height of that board. The currH is obviously the current height - the header's height because I don't want to close the entire window because otherwise you can't open it anymore as you won't see the header and can't click on again duh 😄

Oh almost forget, you start the animation by changing self.isOpen + setting the current time to self.progressStart. The reason why I have a separate self.progressStart is because if the window is not open or not shown, the OnUpdate won't be called, and the animation would stop and only resume when you open it again. Also you can force skip an animation this way if you set the self.progressStart to a time earlier than current time - self.ANIM_TIME (or just simply set it to 0), which would make the animation complete in the next OnUpdate call. Probably not needed in you case, just good to know.

So yeah there you go thats pretty much it, you can apply it to any kind of animation, you just need a minimum value to go from and a maximum value to go to, and multiply the maximum value with the rate.

thank you a lot! So far and for the moment this is what I've achieved: 

 

Spoiler
	def on_update(self):
    # Define the starting positions based on the adplacement boundaries
		adplacement_x = (SCREEN_WIDTH - 1915) / 2 + 13  # Position of the left edge of the adplacement area
		adplacement_width = 35  # Width of the area - From where the sliding effect starts based on above values.

    # Initialize rate
		rate = 0.0  

		if self.animation_in_progress:
			current_time = time.clock()
			elapsed_time = current_time - self.animation_start_time

        # Calculate rate only if slide_duration is greater than 0 to avoid division by zero
			if self.slide_duration > 0:
				rate = min(1.0, elapsed_time / self.slide_duration)  # Progress rate (0.0 to 1.0)

			if rate < 1.0:
				current_image = self.image_buttons[self.image_index - 1]
				next_image = self.image_buttons[self.image_index]

            # Calculate slide amount relative to the adplacement area
				slide_amount = rate * adplacement_width  

            # Update positions based on the intended boundaries
				if self.image_index > 0:  # 
					current_image.SetPosition(adplacement_x - slide_amount, current_image.GetLocalPosition()[1])  # Slide out
					next_image.SetPosition(adplacement_x + (adplacement_width - slide_amount), next_image.GetLocalPosition()[1])  # Slide in
				else:  # When sliding to the right
					current_image.SetPosition(adplacement_x + slide_amount, current_image.GetLocalPosition()[1])  # Slide out
					next_image.SetPosition(adplacement_x - (adplacement_width - slide_amount), next_image.GetLocalPosition()[1])  # Slide in

            # Adjust visibility based on position
				screen_left_bound = adplacement_x  # The left bound position of the images
				screen_right_bound = screen_left_bound + adplacement_width  # Right bound based on the adplacement width

            # For current image
				current_x_pos = current_image.GetLocalPosition()[0]
				if current_x_pos < screen_left_bound:
					current_image.Hide()  # Hide the image if it exceeds the left boundary
				else:
					current_image.Show()  # Show if it's within bounds

            # For next image
				next_x_pos = next_image.GetLocalPosition()[0]
				if next_x_pos > screen_right_bound:
					next_image.Hide()  
				else:
					next_image.Show()  

			else:
				self.animation_in_progress = False
            
            # Reset positions to the intended layout
				current_image = self.image_buttons[self.image_index - 1]
				next_image = self.image_buttons[self.image_index]

            # Reset positions to the adplacement area
				current_image.SetPosition(adplacement_x, current_image.GetLocalPosition()[1])  # Reset current image position
				next_image.SetPosition(adplacement_x, current_image.GetLocalPosition()[1])     # Reset next image position

            # Set both images fully visible at the end of animation
				current_image.Show()
				next_image.Show()

				self.update_image()  # Ensure the next image is correctly positioned
				self.EnableButtons()  # Re-enable buttons after the slide

 

And here's a video: 
https://metin2.download/video/WNXqo40UHsoNek4QsfW7Sr9mD8836KUu/.mp4 - I'm still trying to make the images invisible on the portions where these are outside the specific area. Also, I need to fix the "bug" regarding the left button when changing the image. but at least I have something to work with. 😅
 

Edited by Metin2 Dev International
Core X - External 2 Internal

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.