Thursday, February 22, 2024

Visual Novel with renpy

Another engine, again...

I wanted to test out a Visual Novel Demo. Which means: "Different goals, different methods".

Let me assure you, I am not leaving behind the samples with SDL from the beginning of this blog, I am also not going to stop using Godot for many of my projects (at least for now). This is "only" another extra tool for my bag.

Question: Why now?
Answer: Now, because Ren'Py, like Godot, is in active development. In future iterations compatibility might break, with this Demo I can write down the version that works for the vita before it's too late (you don't want to keep trying versions in the future to find one that can export without crashing).
If a new one works, go ahead and use it, if they don't, you have this one as a back-up.

Question: Why Ren'Py?
Answer: Because Ren'Py is open source and free for commercial use. This engine is also one of the most widely known and used for Visual Novels. It works nicely for PS Vita (loading times aside), and It's easy to use.


With that explained, it's time to get our hands dirty. I decided to call this Demo "Conociendo Hokkaido" to make a somewhat nice presentation of the place in the future and, at the same time, present the Ren'Py
basics too. This time (entry) however, will be mostly about how to set everything up, and make a sample VPK build for the vita. [At the end of the entry, you will find a link to a GitHub repo with this project]

To be fair, most of the engine is pretty straightforward or is explained in their quick start guide https://www.renpy.org/doc/html/quickstart.html (in addition to the whole documentation). However, a few adjustments are necessary to make them work with the PS Vita. Besides, some features (like input) may crash the PS Vita.

The first we need is the engine and the means to export for the vita, to do that, I've used:
Ren'Py Version used: Ren'Py 7.3.5.606 ( https://www.renpy.org/release/7.3.5 )
Ren'Py PSVita Distribution Tool: (crash report says) 7.4.9 Ou ( https://github.com/SonicMastr/renpy-vita )

With that out of hands, let's boot up Ren'Py and create our project:

Since we are making the project to play in the vita, we'll use the console resolution (960, 544). Other than that, just create your project normally:

> 'Create New Project' > Project Name > 'Custom. The GUI is optimized for a 16:9 aspect ratio.'
> WIDTH: 960 > HEIGHT: 544 > Select Accent and Background Colors.

You can see an example in the image below:


When it finishes, it creates a new folder with all the default files. We can now edit them to make our Visual Novel.


We will need to have PS Vita livearea files eventually, I put them here too so they can be found easily.


Besides, I added a few files for my Demo to make it more personal (If we were making a full project, this is how you add them too). [You can omit this step if you are just setting up the engine]

Conociendo Hokkaido > Game > images
Conociendo Hokkaido > Game > audio
Conociendo Hokkaido > Game > gui

Something like the following image:


Back to Ren'Py, if you have received an already created project, and it doesn't show on your project list, you can press on refresh to make them appear.


The basic GUI of the engine displays the following:

> Edit file (it has the code for your game):
    It is useful to say that you can open all rpy files with any text editor of your likeness.
    [This may be worth it to check (or ask) things without opening the whole Ren'Py launcher]


    # options.rpy contains options that can be changed to customize your game.

    # script.rpy contains the actual script for your game

    # gui.rpy contains the GUI Configuration

    # screens.rpy contains the configurations for the screens used to display dialogue to the player.


> Actions (it has some autoconfigurations to check your game's files to look for potential problems)

> Build distributions (is what you expect)
    * The vita export doesn't show here because the tools for it are unofficial.
    

To summarize, in this demo: I've added music, a scene with two minibranches, and one common ending.

* I've also tried to use the input method with the vita keyboard:

```
    $ pName = renpy.input("Write your name and press enter to start the game.", length=10) or "Bunkai"
```

At first, it saves the input (or the lack of it). After that, it glitches out and prompts the keyboard again (this second time the input is not used). As a result, the dialogue for the input prompt and the dialogue right after your first input will be hidden by the keyboard screen.
[None of this happens in the PC version. That resulted in me commenting the input for the time being]


With the basic features somehow finished, and being myself from Spain, I also wanted to have the demo translated (or at least to make the option easy). I used the official documentation for it,
https://www.renpy.org/doc/html/translation.html . However, for me, these explanations were a bit confusing in some parts, and I had to make some trial and error. As a result, I think it's a good idea to share a step by step here with screenshots.

First, we need to know where the default language is stored (it will help us to avoid headaches later):
 `This is called the None language, regardless of what language it actually is.`
We can find the files at: Conociendo Hokkaido > Game > tl


Now it's time to go back to the launcher and generate the translation/localization files.
To do that, go to the 'Generate Translations' section:



A bit overwhelming menu will be displayed, but don't get discouraged, this is what we need to know:


> Language: This is the name of the target language of your translation files.

> Generate empty strings for translations: as the name implies, you will see your Localized lines empty or filled with the original text. (This difference will be shown in the print screen with the translations, where it is the clearest)
 
When the settings are done, press on 'Generate Translations' and the new files will be created.

Before actually translating the sentences, we also want the language option to show in our game. This part is pretty important, and the instructions in the guide could be easily overlooked (or difficult to follow) for a beginner, making a quest to find were the new code goes. To fix this, here's another example:
 
`The Language action can be used to add a language preference to the preferences screen:`

> The path is as follows: 'Project's name' > Game > screens.rpy

Scroll down, until you see something like this:

```
## Preferences screen ##########################################################
##
## The preferences screen allows the player to configure the game to better suit
## themselves.
##
## https://www.renpy.org/doc/html/screen_special.html#preferences
```


Then add/edit this block there:

```
                vbox:
                    style_prefix "pref"
                    label _("Language")
                    textbutton "English" action Language(None)
                    textbutton "EspaƱol" action Language("es_es")
```

[you can put as many extra languages as you want the same way, just add more textbuttons)]


It's time to launch the game within the engine and see the results:
(a new language option has been added)


Now it's time to really translate/localize the game, the files to do that are in the following path:
'Project's name' > Game > tl > 'the previously input name for the new language'
You can see a comparison with the default language from the script in the image below:



'screens.rpy' for menus and preferences
'script.rpy' for the story text
'common.rpy' for prompt messages


The last step is to export our project to play in our beloved PS Vita. To do that, We need to copy the whole project folder from Ren'Py directory to the Ren'Py PS Vita Distribution Tool. It will look like this:


Here, run the 'Ren'Py PS Vita Distribution Tool.exe' and the export config window will be displayed:


The 'Build VPK0' button will not activate until you have filled the blankets, so don't worry. Extra notes to have into account:
 
> write the version parameter with the '00.00' format, or the VPK installation will fail.
> include your 'sce_sys' folder inside your project's folder (like I did in 'Ren'Py)


With that, you have a working Visual Novel Demo for your PS Vita. If you want to try the one from this entry, or use it as the starting point for yours, here's the link to the GitHub repo:
https://github.com/Bunkai9448/ConociendoHokkaido_renpyVita


---

Aditional notes: 

- No self-voicing, as the vita doesn't have TTS

- Load times can be pretty long due to hardware limitation.

- Video playback will not work

- Quiting by the menu will crash the app, but 
doesn't affect anything else.

Tuesday, January 30, 2024

Godot Resize

 This is not really an entry for the PS Vita, but since I want to make things that can be ported, the window resize feature is important. Many times you might want to write specific sizes no matter your targeted screen, however sometimes the default stretching could be useful. This entry is basically an image to show how to configure that:

On your Godot project settings, go to "display/window/stretch/mode" and select "viewport", example below:
 
 
You can configure the kind of resizing/stretching you want to make in the "Aspect" options, some will add black bars and others will stretch the image to fit the screen, chose the one you need for your project there:



Saturday, January 27, 2024

For the Puck

This entry is about the little things before aiming for the control of the puck. In our case, we have decided to use a raycast to check if the player is able to reach the puck, you can see the preparation below:


As you can see, the cast is masked to work only with the puck layer to avoid any confussion with the ground later. The raycast, in charge of this, is called "forThePuck", and it has the enable option checked, with bodies but not areas.

Once we've done that, it's time to make a sanity check before going all out with the puck control and shooting:
 
- Create a new boolean variable initialized at false, this will tell us if the player has the puck or not.
 
- Now write a function that uses the raycast to know if the puck is at player's reach.
 
- Then, finally we add code in the loop to manage the actions for "grabbing it" and "shooting it.
[The script below is only printing text to evaluate both situations, but we'll change that with proper methods in the next steps.]

```
extends RigidBody
# https://docs.godotengine.org/en/3.5/tutorials/physics/rigid_body.html

onready var raycast = get_node("RayCast") # collision layer 1, like anything else
onready var forThePuck = get_node("ForThePuck") # collision layer 2, only the puck
onready var hasPuck = false

func _integrate_forces(_state):
    var dir = Vector3()
    dir.x = Input.get_action_strength("ui_left") - Input.get_action_strength("ui_right")
    dir.z = Input.get_action_strength("ui_up") - Input.get_action_strength("ui_down")

    apply_central_impulse(dir.normalized() /10)

    # Jumping code.
    if on_ground() and Input.is_action_pressed("jump"):
        apply_central_impulse(Vector3(0,1,0))
        
    # Grab puck control
    if puck_on_sight() and !hasPuck:
        get_node("Label").text = "goal"
        hasPuck = true
    
    if !puck_on_sight():
        get_node("Label").text = ""
        hasPuck = false

# Test if there is a body below the player.
func on_ground():
    if raycast.is_colliding():
        return true

# Test if the puck is on sight
func puck_on_sight():
    if forThePuck.is_colliding():
        return true

```


Besisdes, we're going to change the code to display the direction of the player's movement, we had done that in the vehicle node and script.
This is better and less "hacky":
[Warning: the vehicle node wasn't really needed. We'll be cleaning that when we have the puck control done. Now, this new method (code), however, is valid for both.]

```
extends VehicleBody
# Hacky way to make the character look at directions without breaking movement

# Called when the node enters the scene tree for the first time.
func _ready():
    .get_node("WheelRequired").disabled = true
    set_disable_scale(true)

func _integrate_forces(state):
    var dir = Vector3()
    dir.x = Input.get_action_strength("ui_left") - Input.get_action_strength("ui_right")
    dir.z = Input.get_action_strength("ui_up") - Input.get_action_strength("ui_down")
    
    # look at aiming direction properly / still needs a few touches    
    look_at_from_position(get_global_transform().origin, dir , Vector3.UP)
```
 
 

Tuesday, January 23, 2024

Dungeons and Godots

 This is a fairly simple entry, but I wanted to have it here:

I made a character sheet for role playing games as a way to practice the GUI elements and to learn some parameters of the DnD sheet. I'm going to write below a few things to have into account when creating this kind of things in Godot, and also, for tips in some common mistakes that break projects and whose solutions are a nightmare to find, even when they are so simple.

To use a downloaded font (from PC) in TTF or any other format, create a new resource
https://forum.godotengine.org/t/how-do-you-bring-fonts-into-godot-3-0/29601/4
```
  1. Copy your TTF into your project folder
  2. You will see Godot import it as a DynamicFontData in the file browser
  3. In the inspector click on the “new resource” icon and create a new DynamicFont.
  4. In the Font category, click on Font data and choose your TTF
  5. Save the DynamicFont under the name you want (optional)
  6. You can now use this dynamic font where you want, change its size, spacing etc (without altering the original font).
```
And then, you can change the default font in project settings “custom font” property.

To create a toggle button, you need to add a 'check button', with this code below.
```
extends CheckButton

var show = false


func _on_VerTablaModificadores_toggled(_button_pressed):
    $Tabla.visible = !show # Muestra o esconde la tabla segun la variable
    show = !show    # Actualiza la variable acorde a la visibilidad de la imagen en pantalla

```

Use the signals in that node to make it work, 
 
 
For the illustration to change according to your Option Button, you need this code in your illustration's texture rect:
```
extends TextureRect
# Size: x400 y500
# Pos: x540 y20

# Declare member variables here. Examples:
onready var especie = get_parent().get_node("ClaseEspecie/Especie")

# Called when the node enters the scene tree for the first time.
func _ready():
    pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
    var selectedID = especie.get_selected_id()
    var ilustracion = "Ilustraciones/" + especie.get_item_text(selectedID) + ".png"
    texture = load(ilustracion)
 
```

This is the resulted sheet working:

 
Besides, you can find the code for this project freely available at:
With the release app to test if you have a 32 or 64 bits Windows, and a VPK for your PS Vita.

Tuesday, January 16, 2024

SaveData Godot

 Godot SaveLoad

We have a few entries about Godot, now we can learn about how to save/load configuration and data for our games/apps. Besides, I will leave a link to a debug demo in GitHub at the bottom of this entry for those who want to test things.

First, we need to have a scene for loading/saving data. Since we talked about that in previous entries, I will write briefly what you need to have done previously, but I won't go into details:

- A scene: saveLoad.tscn, to work on.
- background, to look cool. (this is optional)
- a nice BGM. (this is optional)
- a character sprite to move, we'll use its position for save/loading tests.
- a nice font, to print the position in screen. (you can omit this if you want to)

Once we have this, image below, we can start with our saveLoad steps.



For making this configuration, we are going to use this documentation: https://docs.godotengine.org/en/3.5/classes/class_configfile.html
Besides, we are basing our code in this video's example:
https://youtu.be/ygGaN1EOQEA?si=9BA3dC4FbtPyKojW

Now, we'll create a new script (saveConfig.gd) to make the save system separately, so we can use it globally and in any project.

For it to be accessed globally as a singleton, you have to go to:
Project > Projects settings


Here you have to go to the autoload label and then click folder icon to load your newly created script (saveConfig.gd).


Then, click on add


to see something like this


After that, it's time to write the code to handle the file where we are going to storage the data to save-load.

```
extends Node2D


var savePath = "res://SaveLoad_test/SaveState.cfg"
var conf = ConfigFile.new()
var loadResult = conf.load(savePath)


# Called when the node enters the scene tree for the first time.
func _ready():
    pass # Replace with function body.


func saveValue(section,key, savedData):
    conf.set_value(section,key,savedData)
    conf.save(savePath)
    
func loadValue(section,key, savedData):
    savedData = conf.get_value(section,key,savedData)
```


With the config code, we need the game to communicate with it to exchange the data. This is done within the game scene script.
```
extends Node2D


var ghostPos = Vector2(0,0)


func _physics_process(_delta):
    if Input.is_action_pressed("ui_start"):
        get_tree().change_scene("res://os_test.tscn")
        
    if Input.is_action_pressed("ui_loadButton"):
        SaveConfig.loadValue("values","ValueOne", ghostPos)
        get_node("KinematicBody2D").set_position(ghostPos)
        
    if Input.is_action_pressed("ui_saveButton"):
        ghostPos = get_node("KinematicBody2D").get_global_transform().origin
        SaveConfig.saveValue("values","ValueOne", ghostPos)

```


With that, you have a saving system done. Since the position saving uses a global variable, it needs a few fixes, but you get the idea, and this is enough for a testing scene.

Finally, as I said at the beginning of the entry, here's the GitHub with the full project:
https://github.com/Bunkai9448/GodotVitaSystemTest
Besides, if you go to the release page, you can try the current beta on your PS Vita.

Monday, January 15, 2024

Godot Audio

In the previous entry we learn about the HUI and GUI, now it's time to add sounds. Godot's documentation for audio can be found here: https://docs.godotengine.org/en/3.5/classes/class_audiostreamplayer.html#class-audiostreamplayer However, as always, I wanted an easy example to work on...

Since I mentioned https://godotengine.org/asset-library/asset/677 in the previous entry, I will be using those as the base for this example, but you can do the same in a clean new project without problems.

First you need to create an AudioStreamPlayer node (you will likely want it to be a child of a main node
to have modularity for future sounds). After that, go to your inspector panel and load your audio:

To do that, use Stream load (image below)


Once we have the node created and the audio load, it's time to create the script to work with. Attach/Create a script in the AudioStreamPlayer's parent node to control the reproduction. Don't worry about the code in this step, we'll do it later.

After that, it's time to make or repurpose a button to play the music. In this sample, we are repurposing the previous ChangeWindowTitle button (since those are values we don't see in the ps vita).
[If you are doing this in a new project, just create a node button and do this step using that button instead]
Go to the node's panel and connect (edit in our case):


Now select the node we have created for the audio, with the script (AudioTest in the image below):


Hint: You can change the name of the signal function, here we've used the old one to make it easier to follow.

The next step is writing the code for it:

```
extends Node


func _ready():
    pass # Replace with function body.

func _on_ChangeWindowTitle_pressed():
    if !$AudioStreamPlayer.playing:
        $AudioStreamPlayer.play()
    else:
        $AudioStreamPlayer.stop()    
    
```

And that's all for today.

Sunday, January 14, 2024

Godots HUI and GUI

 Human User Interface and Guide User Interface.

We all want a good display for menus (settings, shops, etc). In previous entries, I used simple list menus for everything, now it's time to go beyond that. Today I want to write a bit about how to make use of godot's "Control Gallery". ( https://godotengine.org/asset-library/asset/890 )

If we click on that link, and download the assets, we can see a demo like this:

However, it only displays the different buttons and make the animations of them, but they have no actual effect. So, the next step should be making something with them. To do that, we can go to the documentation here: https://docs.godotengine.org/en/stable/tutorials/ui/control_node_gallery.html
After many definitions, there's no actual examples of use, I'll try to fix that here with a mini guide:

First, we need to download the asset and open the project to understand how the visual effects of the buttons are done. We can see those are described in the inspector, on the right side of the window.


You might think that didn't require any explanation. Actually... we are going to use the node, to create a signal,
and that's at the same side of the window. We want to have both clearly differentiated, and that's a good way.

Now, for the main part of the entry, let's make the check button do an action:
    - Create a new script for your parent node. You'll be adding the actions there later. Example below,


    - Click into your selected button. (We'll use the check button, green arrow pointed to the left)
    - Go to the node panel and click to create/connect a new signal (green arrow pointed to the right)



    - This new function with the alarm is the code we want to edit for our purpose,

Example to change the running scene:
```
func _on_Button_pressed():
    get_tree().change_scene("res://SceneName.tscn")
```


A different example, to see the visual effects, is to attach a script to the node and edit its values:
[No need of the use of signals for this] (Here you have the code to update the icon progress bar)
```
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
    if value < 100:
        value = value + 1
    else:
        value = 0
```



That's all for today. I hope this helps to those who didn't know how to start working with them.

PS: Another nice assets and sample to work with that is: https://godotengine.org/asset-library/asset/677 Which also serves as a jumping point to create debugging programs, and system info tools. The documentation for those functions is in: https://docs.godotengine.org/en/3.5/classes/class_os.html). Besides, you might want to call a different script for non-existing OS functions, then you'll need https://docs.godotengine.org/en/3.5/tutorials/scripting/cross_language_scripting.html

PS: If you want to add keyboard/pad control for those buttons, you want to read this https://docs.godotengine.org/en/3.5/tutorials/ui/gui_navigation.html and use:

```
func _ready():
$StartButton.grab_focus()
```
You can watch an example here: https://youtu.be/Mx3iyz8AUAE?si=9BNS2JMtqqwqKXCf

PS2: For a video using scrollbars go to: https://youtu.be/PWP_zGEj4q8?si=WtZRGBvNpUF2VHr1