PC Games
• Orb Tutorials
• 2D shoot 'em up Latest Updates
SDL2 Versus game tutorial
Download keys for SDL2 tutorials on itch.io
The Legend of Edgar 1.37
SDL2 Santa game tutorial 🎅
SDL2 Shooter 3 tutorial
Tags • android (3) • battle-for-the-solar-system (10) • blob-wars (10) • brexit (1) • code (6) • edgar (9) • games (43) • lasagne-monsters (1) • making-of (5) • match3 (1) • numberblocksonline (1) • orb (2) • site (1) • tanx (4) • three-guys (3) • three-guys-apocalypse (3) • tutorials (17) • water-closet (4) Books H1NZ Arriving on the back of a meteorite, an alien pathogen has spread rapidly around the world, infecting all living humans and animals, and killing off all insect life. Only a handful are immune, and these survivors cling desperately to life, searching for food, fresh water, and a means of escape, find rescue, and discover a way to rebuild. |
— Creating a basic widget system — Note: this tutorial assumes knowledge of C, as well as prior tutorials.
Introduction We're going to introduce another new widget now: a slider. This is the sort of widget that one might use for volumes. If you're offering the ability to change the volume of the sound, music, voices, etc. in games, then a slider widget will be most suitable. Extract the archive, run cmake CMakeLists.txt, followed by make, and then use ./widgets05 to run the code. You will see a window open like the one above. Use the Up and Down arrows on you keyboard to change the highlighted menu option. Press Left and Right to change the value of the Slider widgets (sound and music). Note how you can hold the arrows for Sound, but must press it to adjust Music. When you're done, either select Exit or close the window. Inspecting the code We've added a slider widget JSON to our options.json file. The definition of the sound widget is like this: { "type" : "WT_SLIDER", "name" : "sound", "x" : 0, "y" : 300, "label" : "Sound", "step" : 1, "waitOnChange" : 0 } The type is a new type: WT_SLIDER. Most of the other keys will be familiar, though there are two that will come into play later on: step and waitOnChange. Let's get into the code to see how our Slider widget works, starting with defs.h:
We've added the WT_SLIDER value to our enum, so it can be used throughout the code. Next, we've created the actual struct for our new widget in structs.h:
Our SliderWidget will be used as part of a main Widget's data. Like the SelectWidget, the SliderWidget has its own x and y values, so that it can be positions independently. The w and h values are its width and height, which will be used to draw the bar donating the value of the widget. Step will be used to determined how much the widget's value increases or decreased when we interact with it. Finally, waitOnChange will be used to specify whether keys must be pressed to change the value. We'll see how this works when we come to process the widget's logic. Moving onto widgets.c, we've added a new global variable called sliderDelay:
We're setting the value to 0 in initWidgets. Next, we've made a change to createWidget to support the WT_SLIDER enum value:
For all widgets of type WT_SLIDER, we'll call the new createSliderWidget function. This function is quite simple:
We're mallocing a SliderWidget and assigning it to the main Widget's data field. We're also extracting the step and waitOnChange values from the JSON configuration, before finally calculting the main widget's width and height. With our SliderWidget setup, we can now look at the logic side of things. We've made a simple update to doWidgets:
We're decreasing the value of sliderDelay each time doWidgets is called, not allowing it to fall below zero. Otherwise, everything else remains the same. Our main logic support for our SliderWidget is done in changeWidgetValue:
We're now handling the SliderWidget in the WT_SLIDER case statement. The first thing we do is extract the SliderWidget from the widget's data field. We then test to see if we're allowed to process the action, by checking if sliderDelay is 0 or the SliderWidget has waitOnChange set. The sliderDelay is important to stop the SliderWidget's value from changing too quickly when we adjust it; a high framerate would mean it would be near-impossble to update the widget with any good accuracy. If the SliderWidget has waitOnChange set, we'll 0 the left and right arrows, to force them to be pressed again. The waitOnChange is important for the same reason as sliderDelay. If we have a high step set on the SliderWidget, we'll struggle to adjust the value properly due to the speed of the change. The next thing to do is to actually update the SliderWidget's value. We'll do this by adding the SliderWidget's step (multiplied by the dir, to make it negative or positive) to its value. We've decided that our SliderWidget will have a maximum value of 100 and a minimum value of 0, so we'll limit value to this range. In effect, our SliderWidget will represent a percentage from 0 to 100. This will make life easier when it comes to working with the value of the SliderWidget in future. With our value updated, the only two things left to do is reset sliderDelay to 1, to slow speed of the next update, and also to call the Widget's action function pointer, if one has been set. That's our logic done. The only thing left to deal with is drawing out SliderWidget. We'll start with updating drawWidgets:
For SliderWidgets (WT_SLIDER), we're calling a new function: drawSliderWidget. It's defined below:
Like our other widgets, we're drawing the widget in green if it's currently active. Otherwise, we'll render in white. The next thing we do is grab the value of the SelectWidget. We'll take its integer percent value and normalize it to between 0.0 and 1.0, by dividing by 100. After drawing the widget label, we'll draw two rectangles, one filled and one outline. Both rectangles will be drawn using the SliderWidget's x and y coordinates, as well as its width and height. For the filled rectangle, however, we'll multiply the SliderWidget's width by the normalized SliderWidget's value. So, if our SliderWidget's value is 100, the rectangle's width will be the full value of the SliderWidget's w. If it's 50, we'll draw half the value of w. If 28, we'll draw 28% of w, etc. Note how when we call drawRect, we'll adding some inner padding, by adding to the x and y values, but subtracting from the w and h. Our outlined rectangle (drawOutlineRect) is always drawn with the full values of the SliderWidget and always in white. Our SliderWidget is complete! We can now use it in demo.c. As usual, we'll first be updating initDemo:
We only have two SliderWidgets - sound and music. We're getting those by calling getWidget. We're then setting their function pointers (action), and their value attributes, on both the main Widget and the SliderWidget. For the SliderWidget, we're extracting from the main widget's data field, and setting up the x, y, w and h, to set the size of the horizontal bar. We're also setting initial values of 100 for sound (maximum) and 50 for music (halfway). Our function pointers for sound and music references similiarly named functions. The sound function is simple:
We're just grabbing the SliderWidget from the activeWidget's data, and updating the message with the value. We're doing the same thing in the music function:
We now have three different widgets to work with, ones that can handle core functions in a game. Next, we'll look at creating an input widget, so that users can enter text. Purchase The source code for all parts of this tutorial (including assets) is available for purchase: From itch.io It is also available as part of the SDL2 tutorial bundle: |