02-09-2021, 08:55 AM (This post was last modified: 02-09-2021, 08:56 AM by MetalRenard.)
Hey! Going to use this as a place to keep track of my own progress learning GDScript (Godot). Some parts will be relevant to other scripting languages, thought it would be worth sharing and explaining it helps me learn, too.
Followed a few tutorials, watched and read a bunch of stuff. Today, trying to use a 'dictionary' to define level up stats and then call them from another script. First step: Learnt to create a dictionary that holds the data! Kind of a script database of sorts.
02-09-2021, 10:45 AM (This post was last modified: 02-09-2021, 10:55 AM by MetalRenard.)
Part 2!
Goal: Be able to change the character's rotation speed (they look at the mouse).
So the above script runs in the background and is used to store data. Now I want to access this data from another script called 'Player'.
It took me a little while to work this out because it requires specific formatting to tell the engine where to look.
Here's the updated GlobalPlayer script.
Code:
extends Node
var hp_lvl
var shield_lvl
var shot_lvl
var speed_lvl
var rot_lvl
I'm checking to see what the rotation speed of the player is in position 0 of the dictionary's "rotation" array.
Code:
var rot_speed = GlobalPlayer.stats.rotation[0]
The thing that took me ages was learning how to look at data stored in an array which is stored in a dictionary! Finally arrived to this conclusion, very happy.
Next step: Use the _lvl variables to store the player's level and use that to compare with the position in the dictionary.
To accomplish this, I added these varibles above the Player script and compared them to the GlobalPlayer variables.
Code:
var cur_rot_lvl = GlobalPlayer.rot_lvl
And then updated the formula to compare the player's level to the position in the array.
Code:
var rot_speed = GlobalPlayer.stats.rotation[cur_rot_lvl]
My suggestion would be to tell newbies about GDScript's variable scopes or else they might think they might work everywhere...
Believe me, it has happened to many fellas a few times while working on or adapting or editing Ruby scripts.
"For God has not destined us for wrath, but for obtaining salvation through our Lord Jesus Christ," 1 Thessalonians 5:9
Maranatha!
The Internet might be either your friend or enemy. It just depends on whether or not she has a bad hair day.
I'll be honest, I don't really understand the term 'scope' in this setting. I am close to an absolute beginner (prior knowledge only being basic JS and decent html5).
Part 3!
Today's challenge was to create an object that, upon contact, "upgrades" your stats, for now, just the speed stat. You can connect a function in one script to a function in another, in Godot it's done with a 'signal'. You emit it when the two objects overlap and then tell the script to 'observe' it.
The game engine allows for the first part of this to be done automatically.
On the receiving end, you use this code:
This updates the player's level on the GlobalPlayer script which holds the statistics dictionary, updates the current script's speed level so it can find that data in the GlobalPlayer script then updates max_speed accordingly. Max speed is used in another script to define the ships maximum speed like so:
Code:
func _physics_process(delta):
#find out where the mouse is and create the vector from the ship towards it
dir = (get_global_mouse_position() - position).normalized()
#define how the ship moves, max speed and also interpolate its slowdown speed based on the friction variable "fric".
velocity.x = clamp(velocity.x, -max_speed, max_speed)
velocity.y = clamp(velocity.y, -max_speed, max_speed)
move_and_slide(velocity)
(Hint: later there will be a currency system, of course).
Before today, the game checked for input from the 'W' key, (if Input.is_action_pressed("ui_up"): ) and when it was pressed, you accelerated to your max speed (at level 1, that's 100 pixels per second, level 2 is 140).
Now it does that but also checks for the shift key "ui_boost". When pressed, it multiplies your current boost level's dictionary data by your current speed level's dictionary data. All the variables are set before this part.
Code:
if Input.is_action_pressed("ui_boost"):
max_speed = GlobalPlayer.stats.speed[cur_speed_lvl] * boost
Thanks to the lerp (linear interpolation), the camera also zooms out smoothly while boosting. When you release the key, it zooms back in smoothly. Really helps sell the feeling of speed.
Did I say that I also made the ship have particle effects? Well it swaps between two versions, normal or one with more particles when boosting.
Code:
if Input.is_action_just_pressed("ui_boost"):
$Sprite/ShipTrail.emitting = false
$Sprite/ShipTrailBoost.emitting = true
if Input.is_action_just_released("ui_boost"):
$Sprite/ShipTrail.emitting = true
$Sprite/ShipTrailBoost.emitting = false
Now I have to make it update when the player does stuff.
I have variables for current HP (Hull Points), SP (Shield Points) and fuel for the booster.
First, I set up the bars and their labels to match the player's current stat levels. This part happens inside my 'interface' node which is a 'control' node.
Code:
extends Control
var hp
var sp
var fuel
# get and set stats from GlobalPlayer and bar ranges, reset player
func _ready():
hp = GlobalPlayer.stats.hull[GlobalPlayer.hp_lvl]
GlobalPlayer.cur_hp = hp
sp = GlobalPlayer.stats.shield[GlobalPlayer.shield_lvl]
GlobalPlayer.cur_sp = sp
fuel = GlobalPlayer.stats.fuel[GlobalPlayer.fuel_lvl]
GlobalPlayer.cur_fuel = fuel
$MCon/VBCon/HBoxContainer/HBar/HBarCon/HullBar.max_value = hp
$MCon/VBCon/SBar/SBarCon/ShieldBar.max_value = sp
$MCon/VBCon/BBar/BBarContainer/BoostBar.max_value = fuel
I'm not a fan of using absolute paths (I've read it's very easy to break, for example if you change something in one of the folders) so in the future I'm going to look for a way to make it more flexible. For now though, it works. You can see in the picture, it writes how many HP/SP the player has (6 and 6 for now), and the bars are full.
Code:
# Change value of the bars and labels based on current stats
func _process(delta):
# label changes
$MCon/VBCon/HBoxContainer/HBar/Counter/MCon/Label.text = str(GlobalPlayer.cur_hp)
$MCon/VBCon/SBar/Counter/MCon/Label.text = str(GlobalPlayer.cur_sp)
$MCon/VBCon/HBoxContainer/MoneyUI/Counter/Split/MoneyLabel.text = str(GlobalPlayer.money)
# bar progression
$MCon/VBCon/SBar/SBarCon/ShieldBar.value = GlobalPlayer.cur_sp
$MCon/VBCon/HBoxContainer/HBar/HBarCon/HullBar.value = GlobalPlayer.cur_hp
So, this part checks the player's CURRENT HP and SP, then sets the VALUE of the bars and their labels. It also updates the player's money display. Sorry, it's not very well aligned right now but it will be in the final version.
I haven't set this up for the fuel yet, but it works for the HP and SP! Check the 2nd attached image for the visuals.
02-23-2021, 10:40 AM (This post was last modified: 03-01-2021, 02:25 AM by DerVVulfman.)
Today's challenge: Learn how to make menus
Task: Make a simple shop menu for the player to spend their cash on upgrades. Make the buttons clickable and, when clicked, check if they have enough cash then level up the appropriate stat.
First, I set up the buttons, their tags and all that. Here's the code I wrote to make 2 of them function:
Code:
extends Control
var cost = 100
var cost_factor = 0.8
var bcost = 0.0
var tcost = 0.0
Had to take a break for 2 weeks, working on a music project. Plus I have sleep issues so I can't do anything stimulating after 9pm or I won't sleep until 3am. I finish work at 9:30pm 3 times a week so... Not much room for Godot at the moment!
Having said that, I have been thinking about my next step - enemy AI.
I'm planning on giving each enemy 2 collision areas, 1 for detection and 1 for receiving damage. The area will extend in front of the enemy more than behind. I also want them to follow you using pathfinding so... Hope that's not too difficult to do.