How can I translate a STRING into an mathematical operation

Godot Version

v4.3.stable.official [77dcf97d8]

Question

I am trying to create a mathematics related game and I would need to have multiple enemies with different values (numbers and operations; i.e. an enemy for +3, -4, x2, etc.). This values are generated randomly when the enemy is created, since having a different enemy for each operation and number combination sounds ridiculous.
I’m looking for a way to get the operation and value combination in STRING form and use that as a mathematical operation that would apply to the player’s current number. To clarify, the goal of the game is to get your current number (i.e. 3) to match the goal number (i.e. 18) by killing the operation/value enemies, so if the player’s current number is 3 and he wants to reach 18 he would need to kill an enemy displaying the “x6” operation. I need to take that operation from string form and activelly multiply, divide, add, or subtract to the player’s current number.

The easiest way I can think of would be to use the “Expression” class.
I don’t generally use GDScript, but I cobbled together an example code that might help illustrate how it could be done:

func _ready() -> void:
	var expression = Expression.new()
	var error = expression.parse("2x5")
	
	if error != OK:
		print("error parsing expression")
		pass
		
	var result = expression.execute()
	
	if (expression.has_execute_failed()):
		print("error executing expression")
		pass
		
	# Here you can use result!

Of course, you should replace “2x5” with your own expression, and possibly put this into a function instead of calling it in _ready, but I hope that’s a good starting point!

1 Like

Thanks. I will see what I can manage to do, did not know that this class even existed

I managed to do it, firstly I created to global variables: operation and value. Then, I got each operation and value from each enemy instance (these were randomized when the enemy spawned in), when the enemy was killed I changed the global variables to match the enemies operation and values (the operation variable was a String in a array and the value was an Int). Later, in the main game scene, I match the operations names to the operations they need to do using the player’s current number and the value it got from the enemy.

  • Enemy code:
extends CharacterBody2D

var health:int = 2
var value:int
var operation_array:Array = ["Add","Sub","Mult","Div"]
var operation:String


func _ready():
	add_to_group("Enemy")
	
	#randomize numerical value
	value = randi_range(1,10)
	
	#randomize operation
	operation_array.shuffle()
	operation = operation_array[0]


func _physics_process(_delta):
	if health <= 0:
		death()
	
	$Label.text = str(operation) + str(" ") + str(value)

func death():
	OperationControl.current_operation = operation
	OperationControl.current_number = value
	queue_free()
  • World Scene code:
extends Node2D

#Label
@onready var score_label = $ScoreLabel
@onready var goal_label = $GoalLabel
@onready var player_label = $Player/PlayerLabel
#Path
@onready var path_2d = $Path2D
@onready var path_follow_2d = $Path2D/PathFollow2D

const ENEMY = preload("res://enemy.tscn")

var max_enemies = 5

func _ready():
	OperationControl.score = 0
	OperationControl.player_number = 0
	
	randomize_goal_range()

func _process(_delta):
	#Set Lavels
	goal_label.text = str("Goal:") + str(OperationControl.goal-1) + str(" to ") + str(OperationControl.goal+1)
	score_label.text = str("Score:") + str(OperationControl.score)
	player_label.text = str(OperationControl.player_number)
	
	match_operation()
	reach_goal()

func randomize_goal_range():
	OperationControl.goal = randi_range(-20,20)

func match_operation():
	match OperationControl.current_operation:
		"Add":
			OperationControl.player_number += OperationControl.current_number
			OperationControl.current_number = 0
		"Sub":
			OperationControl.player_number -= OperationControl.current_number
			OperationControl.current_number = 0
		"Mult":
			OperationControl.player_number = OperationControl.player_number*OperationControl.current_number
			OperationControl.current_number = 1
		"Div":
			if OperationControl.player_number!=0:
				OperationControl.player_number = round(OperationControl.player_number/OperationControl.current_number)
				OperationControl.current_number = 1
			else: OperationControl.player_number==0

func reach_goal():
	if OperationControl.player_number >=0:
		if OperationControl.player_number >= OperationControl.goal-1 and OperationControl.player_number < OperationControl.goal+1:
			OperationControl.score += 10
			randomize_goal_range()

	else: 
		if OperationControl.player_number < OperationControl.goal-1 and OperationControl.player_number < OperationControl.goal+1:
			OperationControl.score += 10
			randomize_goal_range()

func spawn_enemy():
	path_follow_2d.progress_ratio = randf()
	
	var enemy_inst = ENEMY.instantiate()
	enemy_inst.global_position = path_follow_2d.global_position
	add_child(enemy_inst)

func _on_enemy_spawn_timeout():
	var enemy_group = get_tree().get_nodes_in_group("Enemy")
	if enemy_group.size() < max_enemies:
		spawn_enemy()

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.