Thursday, October 19, 2023

Player and Rigidbody


 Hello there!

After many many many headaches, I found a way to work with the collision between Player and Puck.
Eventually I found this demo https://godotengine.org/asset-library/asset/1291 which uses
Rigidbody to control the player, and has box collisions. Besides, I've swapped the player's shape
with Godot's robot 3d animation from: https://godotengine.org/asset-library/asset/344 and
edited it to my needs. Now I have player movement, puck's collision and a mini rink to test.

Below you can see the current scene (tscn) and code for the player:


Edit: The robot character takes too much resources to load in the PS VITA and the game freezes after pressing the new game button. This means, for now, the robot is discarded and the generic capsule (MeshInstance) is used. [On the PC when I debug the project the resources problem doesn't happen, at all]
 

```
# Player
extends RigidBody


onready var raycast = $RayCast
onready var camera = $Target/Camera
onready var start_position = translation


func _physics_process(_delta):
    var dir = Vector3()
    dir.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
    dir.z = Input.get_action_strength("move_back") - Input.get_action_strength("move_forward")

    # Get the camera's transform basis, but remove the X rotation such
    # that the Y axis is up and Z is horizontal.
    var cam_basis = camera.global_transform.basis
    var basis = cam_basis.rotated(cam_basis.x, -cam_basis.get_euler().x)


    apply_central_impulse(dir.normalized() /5)

    # Jumping code.
    if on_ground() and Input.is_action_pressed("jump"):
        apply_central_impulse(Vector3.UP)


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


And now the player's camera (the one from the player scene, not for the main scene)

```
extends Camera


export var min_distance = 0.5
export var max_distance = 3.0
export var angle_v_adjust = 0.0
var collision_exception = []
var max_height = 2.0
var min_height = 0
onready var target_node: Spatial = get_parent()


func _ready():
    collision_exception.append(target_node.get_parent().get_rid())
    # Detaches the camera transform from the parent spatial node
    set_as_toplevel(true)


func _physics_process(_delta):
    var target_pos: Vector3 = target_node.global_transform.origin
    var camera_pos: Vector3 = global_transform.origin

    var delta_pos: Vector3 = camera_pos - target_pos

    # Regular delta follow

    # Check ranges
    if delta_pos.length() < min_distance:
        delta_pos = delta_pos.normalized() * min_distance
    elif delta_pos.length() > max_distance:
        delta_pos = delta_pos.normalized() * max_distance

    # Check upper and lower height
    delta_pos.y = clamp(delta_pos.y, min_height, max_height)
    camera_pos = target_pos + delta_pos

    look_at_from_position(camera_pos, target_pos, Vector3.UP)

    # Turn a little up or down
    var t = transform
    t.basis = Basis(t.basis[0], deg2rad(angle_v_adjust)) * t.basis
    transform = t
```


If you try that, your character will fall to the ground due to the physics, and you'll see a capsule rotating around the floor. To fix that, you have to go to the inspector (in your rigidbody) and lock the angular Axis. Example in the image below:






Monday, October 16, 2023

3D objects position - scoring

Now that we have a way to locate our objects (puck and net) in the screen grid space, it's time to make a function to check if someone has scored. To evaluate this condition, we need to know if the puck is in a certain range of the space:

(Note: I used the player object as a way to easily test the code.)
 
Is the puck between the net's lateral posts?
 
```
signal goal
func _process(delta):
    var netPos = netA.get_global_transform().origin.x
    var pPosition = get_global_transform().origin.x
    # Puck between the posts
    if pPosition > (netA_width/2) and pPosition < (netPos + netA_width):
        emit_signal("goal", pPosition)
       
onready var netA = .get_parent().get_node("GoalNet")
onready var netA_x = netA.get_node("StaticBody_postR").get_global_transform().origin.x
onready var netA_x2 = netA.get_node("StaticBody_postL").get_global_transform().origin.x
onready var netA_width = netA_x - netA_x2
```

Is the puck inside the net and not past the net?
 
```
signal goal
func _process(delta):
    var netPos = netA.get_global_transform().origin.z
    var pPosition = get_global_transform().origin.z
    # Puck inside the net
    if pPosition > (netPos - netA_depth) and (pPosition < netPos):
        emit_signal("goal", pPosition)

onready var netA = .get_parent().get_node("GoalNet")
onready var netA_z = netA.get_node("StaticBody_postZ").get_global_transform().origin.z
onready var netA_z2 = netA.get_node("StaticBody_netZ2").get_global_transform().origin.z
onready var netA_depth = netA_z - netA_z2
```
 

Is the puck between the rink's floor and the top post?

```
```

Finally, we merge all those evaluations into one script:

```
signal goal
func _process(delta):
    var netPos = netA.get_global_transform().origin
    var pPosition = get_global_transform().origin
    # Puck inside the net
    if pPosition.z > (netPos.z - netA_depth) and (pPosition.z < netPos.z) \
    and pPosition.x > (netA_width/2) and pPosition.x < (netPos.x + netA_width):
        emit_signal("goal", pPosition)

onready var netA = .get_parent().get_node("GoalNet")

onready var netA_x = netA.get_node("StaticBody_postR").get_global_transform().origin.x
onready var netA_x2 = netA.get_node("StaticBody_postL").get_global_transform().origin.x
onready var netA_width = netA_x - netA_x2

onready var netA_z = netA.get_node("StaticBody_postZ").get_global_transform().origin.z
onready var netA_z2 = netA.get_node("StaticBody_netZ2").get_global_transform().origin.z
onready var netA_depth = netA_z - netA_z2

```





Friday, October 13, 2023

Godot 3.5 AI

Since one of the "near" future steps for the ice puck game I had to see how to implement the NPC AI, and I want to leave a few documentation/guide videos. All with explanations and examples, plus a description of mine here so you can remember at a glance. [Remember you can use any of them if it fits you, I'm only giving hints]

State machine
https://youtu.be/RzUkBT7QwrU?si=OirslGHuHIs2kIDk
These are your usual platformer ones, mario like, where the enemy has a pattern that repeats over and over, no matter what.

Behaviour tree
https://youtu.be/YHUQY2Kea9U?si=oxl2viKZpWvxe0mG
These are more seen in fighting and shooter games, I believe racing games could go here as well. The enemy has a tree and different paths with minimum weights, to select the most efficient to their task. Your enemy doesn't take into account your life or score, it wants to finish you. 

GOAP
https://youtu.be/LhnlNKWh7oc?si=ct5vAyN4yCuv3nf_
The Goal Oriented Action Planning (GOAP),
which is the one I'm probably going to use. This one uses the priorities given for their goals, hence why for a sport game could be pretty useful. For example, the enemy takes into account if it has more or less goals than you, to decide if defence the net or attack.


Wednesday, October 11, 2023

3D objects position

 So... Another Godot for the PS Vita entry here.

There are a few ways to check if the puck enters the net, and for the NPC to follow the puck, I need to know its position. Therefor I had to see how to manage it in Godot 3.5, and that's what I want to write here for the people who want to do the same.

WARNING: This is the way I came up with. There could be more, and it may be different in other Godot versions, but for me, it works. Besides, this can be reused in any other project easily. Last but not least, the code and Idea below shows values in screen to give you an idea of how to use it, the numbers are by no means used in practice yet (I save that for another entry, maybe).

Without further ado, Code to see the positions of 3d objects in Godot 3.5

First, I took the "3D Squash the Creeps starter project" from https://github.com/gdquest-demos/godot-3-getting-started-2021/releases/tag/1.0.0 to have a test base (this way I don't have to create a new scene, and anyone can follow along without much problem). I cleaned a bit tho, no need of the mobs group or the scoring system for my test.






Then, I created and used signals to send the numbers from the Player and the creeper(Mob) to a UserInterface/Label node(ScoreLabel), so they can be printed in screen.  My added code is below:

```
# Creeper Code

signal creep
func _process(delta):
    var cPosition = get_global_transform()
    emit_signal("creep", str(cPosition))
```

```
# Player Code

signal player
func _process(delta):
    var pPosition = get_global_transform()
    emit_signal("player", str(pPosition))
```

Once I had the numbers, I just created two local variables on the label and printed them on screen.
```
# textPositions label code

extends Label

var player_position = 0
var creep_position = 0


func _on_Mob_creep(cPosition):
    creep_position =  cPosition

func _on_Player_player(pPosition):
    player_position =  pPosition

func _process(delta):
#    text = "PlayerPos: %s " % player_position
#    text = "CreeperPos: %s " % creep_position
    text = "PlayerPos: %s \n" %player_position + "CreeperPos: %s" %creep_position
```
 
Here you can see images of the result with the player in various positions




More on the position and the get_global_transform() here: https://ask.godotengine.org/40558/follow-node-movement-but-ignore-rotation

Furthermore, if you want the net's position from the label node, you can use:
(In my case, the label was the grand-grandchild of the player's sibling, so a few parents were needed)

```
onready var netA = get_parent().get_parent().get_parent().get_node("GoalNet").get_global_transform().origin
```

Saturday, October 7, 2023

New Engine

I had a secret halted demo game for a long time (due to some nasty bugs), so when I found out about the new Homebrew contest for the vita I knew it was time to squash them and release it: https://fuhen.homebrew-contest.com/submissions/23/ 
 
Besides, thanks to the FuHEN Homebrew Contest for PS VITA, I discoverd some options that I didn't know. And since this blog is to develope homebrew for that console, I decided to add the info here. After reading around the resources page: https://fuhen.homebrew-contest.com/resources/ I discover a new interesting option for coding my Ice Puck homebrew, which is the Godot Engine: https://github.com/SonicMastr/godot-vita/releases/tag/3.5-rc5-vita1 
 
Official documentation for Godot 3.5 here:

Then, I tried to make a test exporting the game "3D Squash the Creeps starter project" (which also is a good introduction to the engine for beginners). A video explanation of how to code it can be found here: https://www.youtube.com/watch?v=YiE9tcoCfhE and the code's official repo is here: https://github.com/gdquest-demos/godot-3-getting-started-2021/releases/tag/1.0.0 
 

 As explained in the README, for it to work on the vita, we need to make a few adjustments to the project settings. 
(For newbies who don't find that config in the engine) I will explain those steps below, with screenshots: 
 
 Go to Project > "Project Settings..." 
 

 
 
Click on Search and type "GLE2" 
Then click Quality and mark the box "Fallback to GLE2" 
 
 

 
Next it's turn to: Click on Search and type "ETC2" 
Then click on VRAM compression and mark the box "Import ETC2"
 
 
 
After that, close the window. 
 
 
Finally to export your game: 
 
Go to Project > "Export..." 

When it asks for an export template, choose and load the "vita_template_3.5.rc5.tpz" file from the github.

 



Time to make and play your own games!

Sunday, October 1, 2023

Some hockey flowcharts

 These are some basic flowcharts to have an idea of what each of the key game objects does or doesn't and how.

The room should load the board and the rink first, and that's our first diagram.

Score Board and Timer

After the board come the players/skaters and the puck

Players / Skaters








The Puck

 

Extra notes: Game wise, the most work will be into how the players behave and how the puck react to them and the rink limits [This means that, in the future, the flowcharts may be updated]. Besides, there will be more charts for extra objects positions and updates, e.g. the nets or the rink limits. In addition, later on, we'll also have menu and options.



Friday, May 19, 2023

Modularity

A well-designed program must be modular if it has a big size, and guess what, these projects are big. So, for this entry, we will be making a modular base for our program. This means, we want at least 3 modules (files):

  • main program

----------------------------------------------------------