random flower

random flower

extends Sprite

var r

func _ready():
	r = randi()*(self.get_hframes()*self.get_vframes())
	self.set_frame(r);
	pass

extends Sprite

# member variables here, example:
# var a=2
# var b="textvar"
var r

func _ready():
	#r = rand()*self.get_hframes()
	#self.set_frame(r);
	pass


Fix for omnidirectional attack

Fix for omnidirectional attack

var bag

var enemy_templates = {
    #easy
    'shia' : preload("res://scripts/enemies/shia.gd"),
    'retarded_rat' : preload("res://scripts/enemies/retarded_rat.gd"),
    'fat_rat' : preload("res://scripts/enemies/fat_rat.gd"),
    'jumping_rat' : preload("res://scripts/enemies/jumping_rat.gd"),
    'spider' : preload("res://scripts/enemies/spider.gd"),

    #boss
    'shia_prime' : preload("res://scripts/enemies/shia_prime.gd"),
    'doge_prime' : preload("res://scripts/enemies/doge_prime.gd"),
    'noser_prime' : preload("res://scripts/enemies/noser_prime.gd"),
    'noser_prime_medium' : preload("res://scripts/enemies/noser_prime_medium.gd"),
    'noser_prime_small' : preload("res://scripts/enemies/noser_prime_small.gd"),
    'noser_prime_tiny' : preload("res://scripts/enemies/noser_prime_tiny.gd"),
}

var enemy_difficulties = [
    [],
    ['retarded_rat', 'fat_rat', 'jumping_rat', 'spider'],
    ['shia'],
]

var enemies_list = {}

func _init_bag(bag):
    self.bag = bag

func spawn(name, map_position):
    var global_position = self.bag.room_loader.translate_position(map_position)
    return self.spawn_global(name, global_position)

func spawn_global(name, global_position):
    var new_enemy = self.enemy_templates[name].new(self.bag)
    new_enemy.spawn(global_position)
    self.add_enemy(new_enemy)
    return new_enemy

func reset():
    for enemy in self.enemies_list:
        self.enemies_list[enemy].detach()
    self.enemies_list.clear()

func add_enemy(enemy):
    self.enemies_list[enemy.get_instance_ID()] = enemy

func del_enemy(enemy):
    self.enemies_list.erase(enemy.get_instance_ID())
    if self.enemies_list.size() == 0:
        self.bag.room_loader.open_doors()
        self.bag.game_state.current_cell.clear = true

func get_enemies_near_object(object, attack_range, attack_direction, attack_width):
    var result = []
    for instance_id in self.enemies_list:
        if self.is_enemy_in_cone(self.enemies_list[instance_id], object, attack_range, attack_direction, attack_width):
            result.append(self.enemies_list[instance_id])

    return result

func is_enemy_in_cone(enemy, object, attack_range, attack_direction, attack_width):
    var enemy_position
    var object_position
    var position_delta
    var attack_vector
    var angle
    var melee_range = 3

    var distance = enemy.calculate_distance_to_object(object)

    if distance < melee_range:
        return true

    if distance < attack_range:
        enemy_position = enemy.get_pos()
        attack_vector = Vector2(attack_direction[0], attack_direction[1])
        object_position = object.get_pos()
        position_delta = Vector2(enemy_position.x - object_position.x, enemy_position.y - object_position.y)
        angle = attack_vector.angle_to(position_delta)

        if abs(angle) < attack_width:
            return true
    return false

func get_random_enemy_name(difficulty):
    randomize()
    var apropriate_enemies = self.enemy_difficulties[difficulty]
    return apropriate_enemies[randi() % apropriate_enemies.size()]

var bag

var enemy_templates = {
    #easy
    'shia' : preload("res://scripts/enemies/shia.gd"),
    'retarded_rat' : preload("res://scripts/enemies/retarded_rat.gd"),
    'fat_rat' : preload("res://scripts/enemies/fat_rat.gd"),
    'jumping_rat' : preload("res://scripts/enemies/jumping_rat.gd"),
    'spider' : preload("res://scripts/enemies/spider.gd"),

    #boss
    'shia_prime' : preload("res://scripts/enemies/shia_prime.gd"),
    'doge_prime' : preload("res://scripts/enemies/doge_prime.gd"),
    'noser_prime' : preload("res://scripts/enemies/noser_prime.gd"),
    'noser_prime_medium' : preload("res://scripts/enemies/noser_prime_medium.gd"),
    'noser_prime_small' : preload("res://scripts/enemies/noser_prime_small.gd"),
    'noser_prime_tiny' : preload("res://scripts/enemies/noser_prime_tiny.gd"),
}

var enemy_difficulties = [
    [],
    ['retarded_rat', 'fat_rat', 'jumping_rat', 'spider'],
    ['shia'],
]

var enemies_list = {}

func _init_bag(bag):
    self.bag = bag

func spawn(name, map_position):
    var global_position = self.bag.room_loader.translate_position(map_position)
    return self.spawn_global(name, global_position)

func spawn_global(name, global_position):
    var new_enemy = self.enemy_templates[name].new(self.bag)
    new_enemy.spawn(global_position)
    self.add_enemy(new_enemy)
    return new_enemy

func reset():
    for enemy in self.enemies_list:
        self.enemies_list[enemy].detach()
    self.enemies_list.clear()

func add_enemy(enemy):
    self.enemies_list[enemy.get_instance_ID()] = enemy

func del_enemy(enemy):
    self.enemies_list.erase(enemy.get_instance_ID())
    if self.enemies_list.size() == 0:
        self.bag.room_loader.open_doors()
        self.bag.game_state.current_cell.clear = true

func get_enemies_near_object(object, attack_range, attack_direction, attack_width):
    var result = []
    for instance_id in self.enemies_list:
        if self.is_enemy_in_cone(self.enemies_list[instance_id], object, attack_range, attack_direction, attack_width):
            result.append(self.enemies_list[instance_id])

    return result

func is_enemy_in_cone(enemy, object, attack_range, attack_direction, attack_width):
    var enemy_position
    var object_position
    var position_delta_x
    var position_delta_y
    var angle
    var back_offset = 3
    var melee_range = 3

    var distance = enemy.calculate_distance_to_object(object)

    if distance < melee_range:
        return true

    if distance < attack_range:
        enemy_position = enemy.get_pos()
        object_position = object.get_pos() - Vector2(attack_direction[0], attack_direction[1]) * back_offset
        position_delta_x = enemy_position.x - object_position.x
        position_delta_y = enemy_position.y - object_position.y
        angle = atan2(position_delta_x * attack_direction[1] - position_delta_y * attack_direction[0], position_delta_x * attack_direction[0] + position_delta_y * attack_direction[1] )
        if abs(angle) < attack_width:
            return true
    return false

func get_random_enemy_name(difficulty):
    randomize()
    var apropriate_enemies = self.enemy_difficulties[difficulty]
    return apropriate_enemies[randi() % apropriate_enemies.size()]


Cleared starting room

Cleared starting room


Tried to finish zombieMove, but bug

Tried to finish zombieMove, but bug

This commit is to document a bug, so I can reproduce it at will.  Run
the program and see that the output is supposed to be texture, but
instead is a 'Nil'.

extends Node

#get_node("/root/global").enteringOS               <--This is the proper method to quit to desktop.
#get_node("/root/global").enteringMenu             <--This is the proper method to get to the main menu.
#get_node("/root/global").currentDifficulty        <--This is the proper method to get the difficulty.
#get_node("/root/global").disableInputForXMs(1000) <--This is the proper method to rapid inputs.

#Time based variables.
#var eclipseRatio = null

#Player stuff.
var playerScore = null
var playerTime = null #Units are in seconds.
var playerDifficulty = null #This has to be between 0 and 3 to match the size of xSizeArray and ySizeArray.
#var specialAbilityAmmo = null
var tombArray = []
var tombOrigen = null
var tombs = null
var tombNumberTotal = 0
var zombieData = [] #[{"node":sub-scene, "zombieTime":time, "zombieStart":rand_range(0, 4), "zombieType":"type", "tombType":"type"}, {...}, ...]
#zombieData[0] = {"node":sub-scene, "zombieTime":time}
#zombieData[1].node = sub-scene
const xTombSpacing = 200
const yTombSpacing = 175
var tombStyle = null
var tombList = []
var time = null

var xSizeArray = [3, 3, 4, 6] #[Easy, Normal, Hard, Insane]
var ySizeArray = [1, 2, 3, 3] #[Easy, Normal, Hard, Insane]
var playerHealth = [3, 3, 3, 3] #[Easy, Normal, Hard, Insane]
var voidTombs = [0, 1, 2, 3] #[Easy, Normal, Hard, Insane] These tomb placeholders do not have any zombies coming up.
var howDiedTombCount = 3 #this is a count of the number of different flavor texts that go on tombstones.
#var tombArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ",", ".", "_", "-"]

func zombieStart(index): #Don't call unless zombie is below ground.
	zombieData[index].zombieTime = rand_range(1.85, 2.15) #This needs to be in seconds to match playerTime.
	zombieData[index].zombieStart = max(playerTime, 1) + rand_range(0, 4) #This needs to be in seconds to match playerTime.

	if zombieData[index].node.get_node("rubbleHole").visible:
		zombieData[index].zombieType = "missing"
	else:
		if floor(rand_range(0, 3)) == 0:
			zombieData[index].zombieType = "hat"
		else:
			zombieData[index].zombieType = "normal"

func zombieDataInit():
	createTombList()

	for c in range(playerHealth[playerDifficulty]): #Make normal tombs for player health.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("normalTomb").show()
		tombList[i].get_node("frontHole").show()
		tombList[i].get_node("backHole").show()
		#tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for c in range(voidTombs[playerDifficulty]): #Make void tombs.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for i in range(tombList.size()): #Make the rest of the tombs.
		if tombList.empty():
			continue
		var r = floor(rand_range(0, 2))
		if r == 0:
			tombList[i].get_node("brokenTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		elif r == 1:
			tombList[i].get_node("missingTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		else:
			pass

	createTombList()
	zombieData.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			zombieData.append({"node":tombArray[x][y], "zombieTime":0, "zombieStart":0, "MARGIN_TOP":tombArray[x][y].get_margin(MARGIN_TOP)})
	for c in range(zombieData.size()):
		if zombieData.empty():
			continue

		print(zombieData)
		print(zombieData[c])
		print(zombieData[c].node)
		print(zombieData[c].node.get_node("rubbleHole"))
		print(zombieData[c].node.get_node("rubbleHole").visible)

		if zombieData[c].node.get_node("rubbleHole").visible:
			zombieData[c].zombieType = "missing"
		zombieStart(c)

func getIndexFromNode(node): #When passed a node, find that node's index inside of zombieData.
	for c in range(zombieData.size()):
		if zombieData.empty():
			continue
		if zombieData[c].node == node:
			return c
	return null

func _ready():
	get_tree().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	set_process(true) #Enables: _process(delta) to run every frame.
	playerDifficulty = get_node("/root/global").currentDifficulty

	tombs = get_node("tombs")

	#for g in range(glyphArray.size()):
	#	n = load("res://scene/getNameGlyph.xscn").instance()
	#	glyph.add_child(n)

	tombArray.resize(0) #This initiallizes the tombArray to empty before we start adding to it.
	for x in range(xSizeArray[playerDifficulty]):
		tombArray.append([])
		for y in range(ySizeArray[playerDifficulty]):
			tombArray[x].append(load("res://scene/zombiesGoTomb.xscn").instance())
			#print("Hello World " + str(x) + ", " + str(y))
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			tombArray[x][y].set_margin(MARGIN_LEFT, 1280/2 - xSizeArray[playerDifficulty]*xTombSpacing/2 + x * xTombSpacing + floor(rand_range( -xTombSpacing*.2, xTombSpacing*.2)))
			tombArray[x][y].set_margin(MARGIN_TOP, 720/2 - ySizeArray[playerDifficulty]*yTombSpacing/2  + y * yTombSpacing)
			tombs.add_child(tombArray[x][y])

	#Init settings for round.
	#eclipseRatio = (difficulty - 1) * 0.2
	playerScore = 0
	playerTime = 0
	#specialAbilityAmmo = 0

	zombieDataInit()

func createTombList(): #Create List
	tombList.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			tombList.append(tombArray[x][y])

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST):
		#Submit current game and save highArray before exiting.
		get_node("/root/global").enteringOS = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _process(delta):
	#This is ran every frame.
	#get_node("/root/global").timeString(time)
	playerTime = playerTime + delta
	get_node("displayPlayerTimeOnScreen").set_text(get_node("/root/global").timeString(playerTime))
	time = int(floor(playerTime))
	# Check for death.
	if playerDifficulty == 3:
		#isDied()= true
		pass

	zombieMove()

		#if time <= 2:
		#	zombieMove() = true
		#else:
		#	zombieMove() = false

func isDied():
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(playerScore, playerTime)

func _on_backGround_pressed():
	if get_node("/root/global").isInputEnabled():
		#Submit current game and save highArray before ending round.
		#updateHighScore(score, time)
		get_node("/root/global").enteringMenu = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func zombieMove(): #Move zombies up, then down, based on playerTime, zombieTime, zombieStart.
	for c in range(zombieData.size()):

		if zombieData.empty():
			continue

		if zombieData[c].zombieType == "normal":
			zombieData[c].node.get_node("zombieNormal").show()
			zombieData[c].node.get_node("zombieHat").hide()
			if playerTime < zombieData[c].zombieStart: #Before start
				zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP, 0)

			elif playerTime < (zombieData[c].zombieStart + (zombieData[c].zombieTime / 2)): #Going up
				zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP,  ((-190 / zombieData[c].zombieTime) * playerTime) + (zombieData[c].zombieStart * (190 / zombieData[c].zombieTime)))

			elif playerTime < (zombieData[c].zombieStart + zombieData[c].zombieTime): #Going down
				zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP,  ((190 / zombieData[c].zombieTime) * playerTime) - ((zombieData[c].zombieStart + zombieData[c].zombieTime) * (190 / zombieData[c].zombieTime)))

			else: #playerTime >= (zombieData[c].zombieStart + zombieData[c].zombieTime): #Reset zombieStart
				zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP, 0)
				zombieStart(c)

		elif zombieData[c].zombieType == "hat":
			zombieData[c].node.get_node("zombieNormal").hide()
			zombieData[c].node.get_node("zombieHat").show()
			if playerTime < zombieData[c].zombieStart: #Before start
				zombieData[c].node.get_node("zombieHat").set_margin(MARGIN_TOP, 0)

			elif playerTime < (zombieData[c].zombieStart + (zombieData[c].zombieTime / 2)): #Going up
				zombieData[c].node.get_node("zombieHat").set_margin(MARGIN_TOP,  ((-190 / zombieData[c].zombieTime) * playerTime) + (zombieData[c].zombieStart * (190 / zombieData[c].zombieTime)))

			elif playerTime < (zombieData[c].zombieStart + zombieData[c].zombieTime): #Going down
				zombieData[c].node.get_node("zombieHat").set_margin(MARGIN_TOP,  ((190 / zombieData[c].zombieTime) * playerTime) - ((zombieData[c].zombieStart + zombieData[c].zombieTime) * (190 / zombieData[c].zombieTime)))

			else: #playerTime >= (zombieData[c].zombieStart + zombieData[c].zombieTime): #Reset zombieStart
				zombieData[c].node.get_node("zombieHat").set_margin(MARGIN_TOP, 0)
				zombieStart(c)
		elif zombieData[c].zombieType == "missing":
			zombieData[c].node.get_node("zombieNormal").hide()
			zombieData[c].node.get_node("zombieHat").hide()
		else:
			print("Variable zombieType is set to an incorrect value.")
			continue

extends Node

#get_node("/root/global").enteringOS               <--This is the proper method to quit to desktop.
#get_node("/root/global").enteringMenu             <--This is the proper method to get to the main menu.
#get_node("/root/global").currentDifficulty        <--This is the proper method to get the difficulty.
#get_node("/root/global").disableInputForXMs(1000) <--This is the proper method to rapid inputs.

#Time based variables.
#var eclipseRatio = null

#Player stuff.
var playerScore = null
var playerTime = null #Units are in seconds.
var playerDifficulty = null #This has to be between 0 and 3 to match the size of xSizeArray and ySizeArray.
#var specialAbilityAmmo = null
var tombArray = []
var tombOrigen = null
var tombs = null
var tombNumberTotal = 0
var zombieData = [] #[{"node":tomb, "zombieTime":time, "zombieStart":rand_range(0, 4)}, {...}, ...]
#zombieData[0] = {"node":tomb, "zombieTime":time}
#zombieData[1].node = tomb
const xTombSpacing = 200
const yTombSpacing = 175
var tombStyle = null
var tombList = []
var time = null

var xSizeArray = [3, 3, 4, 6] #[Easy, Normal, Hard, Insane]
var ySizeArray = [1, 2, 3, 3] #[Easy, Normal, Hard, Insane]
var playerHealth = [3, 3, 3, 3] #[Easy, Normal, Hard, Insane]
var voidTombs = [0, 1, 2, 3] #[Easy, Normal, Hard, Insane] These tomb placeholders do not have any zombies coming up.
var howDiedTombCount = 3 #this is a count of the number of different flavor texts that go on tombstones.
#var tombArray = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ",", ".", "_", "-"]

func zombieStart(index): #Don't call unless zombie is below ground.
	zombieData[index].zombieTime = rand_range(1.85, 2.15) #This needs to be in seconds to match playerTime.
	zombieData[index].zombieStart = max(playerTime, 1) + rand_range(0, 4) #This needs to be in seconds to match playerTime.

func zombieDataInit():
	zombieData.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			zombieData.append({"node":tombArray[x][y], "zombieTime":0, "zombieStart":0, "MARGIN_TOP":tombArray[x][y].get_margin(MARGIN_TOP)})
	for c in range(zombieData.size()):
		if zombieData.empty():
			continue
		zombieStart(c)

func getIndexFromNode(node): #When passed a node, find that node's index inside of zombieData.
	for c in range(zombieData.size()):
		if zombieData.empty():
			continue
		if zombieData[c].node == node:
			return c
	return null

func _ready():
	get_tree().set_auto_accept_quit(false) #Enables: _notification(what) to recieve MainLoop.NOTIFICATION_WM_QUIT_REQUEST
	set_process(true) #Enables: _process(delta) to run every frame.
	playerDifficulty = get_node("/root/global").currentDifficulty

	tombs = get_node("tombs")

	#for g in range(glyphArray.size()):
	#	n = load("res://scene/getNameGlyph.xscn").instance()
	#	glyph.add_child(n)

	tombArray.resize(0) #This initiallizes the tombArray to empty before we start adding to it.
	for x in range(xSizeArray[playerDifficulty]):
		tombArray.append([])
		for y in range(ySizeArray[playerDifficulty]):
			tombArray[x].append(load("res://scene/zombiesGoTomb.xscn").instance())
			#print("Hello World " + str(x) + ", " + str(y))
			#MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM
			tombArray[x][y].set_margin(MARGIN_LEFT, 1280/2 - xSizeArray[playerDifficulty]*xTombSpacing/2 + x * xTombSpacing + floor(rand_range( -xTombSpacing*.2, xTombSpacing*.2)))
			tombArray[x][y].set_margin(MARGIN_TOP, 720/2 - ySizeArray[playerDifficulty]*yTombSpacing/2  + y * yTombSpacing)
			tombs.add_child(tombArray[x][y])

	#Init settings for round.
	#eclipseRatio = (difficulty - 1) * 0.2
	playerScore = 0
	playerTime = 0
	#specialAbilityAmmo = 0

	createTombList()

	for c in range(playerHealth[playerDifficulty]): #Make normal tombs for player health.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("normalTomb").show()
		tombList[i].get_node("frontHole").show()
		tombList[i].get_node("backHole").show()
		#tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for c in range(voidTombs[playerDifficulty]): #Make void tombs.
		if tombList.empty():
			continue
		var i = floor(rand_range(0, tombList.size()))
		tombList[i].get_node("rubbleHole").show()
		tombList.remove(i)

	for i in range(tombList.size()): #Make the rest of the tombs.
		if tombList.empty():
			continue
		var r = floor(rand_range(0, 2))
		if r == 0:
			tombList[i].get_node("brokenTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		elif r == 1:
			tombList[i].get_node("missingTomb").show()
			tombList[i].get_node("frontHole").show()
			tombList[i].get_node("backHole").show()
			#tombList[i].get_node("rubbleHole").show()
		else:
			pass

	createTombList()
	zombieDataInit()

func createTombList(): #Create List
	tombList.resize(0)
	for x in range(xSizeArray[playerDifficulty]):
		for y in range(ySizeArray[playerDifficulty]):
			tombList.append(tombArray[x][y])

func _notification(what):
	if (what==MainLoop.NOTIFICATION_WM_QUIT_REQUEST):
		#Submit current game and save highArray before exiting.
		get_node("/root/global").enteringOS = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func _process(delta):
	#This is ran every frame.
	#get_node("/root/global").timeString(time)
	playerTime = playerTime + delta
	get_node("displayPlayerTimeOnScreen").set_text(get_node("/root/global").timeString(playerTime))
	time = int(floor(playerTime))
	# Check for death.
	if playerDifficulty == 3:
		#isDied()= true
		pass

	zombieMove()

		#if time <= 2:
		#	zombieMove() = true
		#else:
		#	zombieMove() = false

func isDied():
	get_node("/root/global").enteringMenu = true
	get_node("/root/global").updateHighScore(playerScore, playerTime)

func _on_backGround_pressed():
	if get_node("/root/global").isInputEnabled():
		#Submit current game and save highArray before ending round.
		#updateHighScore(score, time)
		get_node("/root/global").enteringMenu = true
		get_node("/root/global").updateHighScore(rand_range(0, 9999), rand_range(0, 59))

func zombieMove(): #Move zombies up, then down, based on playerTime, zombieTime, zombieStart.
	for c in range(zombieData.size()):
		if zombieData.empty():
			continue
		zombieData[c].node.get_node("zombieNormal").show()
		if playerTime < zombieData[c].zombieStart: #Before start
			zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP, 0)

		elif playerTime < (zombieData[c].zombieStart + (zombieData[c].zombieTime / 2)): #Going up
			zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP,  ((-190 / zombieData[c].zombieTime) * playerTime) + (zombieData[c].zombieStart * (190 / zombieData[c].zombieTime)))

		elif playerTime < (zombieData[c].zombieStart + zombieData[c].zombieTime): #Going down
			zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP,  ((190 / zombieData[c].zombieTime) * playerTime) - ((zombieData[c].zombieStart + zombieData[c].zombieTime) * (190 / zombieData[c].zombieTime)))

		else: #playerTime >= (zombieData[c].zombieStart + zombieData[c].zombieTime): #Reset zombieStart
			zombieData[c].node.get_node("zombieNormal").set_margin(MARGIN_TOP, 0)
			zombieStart(c)


Set the reset position from the initial start position in KC3D

extends KinematicBody

const MAX_SPEED = 3
const JUMP_SPEED = 5
const ACCELERATION = 2
const DECELERATION = 4

onready var camera = $Target/Camera
onready var gravity = -ProjectSettings.get_setting("physics/3d/default_gravity")
onready var start_position = translation
var velocity: Vector3

func _physics_process(delta):
	if Input.is_action_just_pressed("exit"):
		get_tree().quit()
	if Input.is_action_just_pressed("reset_position"):
		translation = start_position

	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)
	dir = basis.xform(dir)

	# Limit the input to a length of 1. length_squared is faster to check.
	if dir.length_squared() > 1:
		dir /= dir.length()

	# Apply gravity.
	velocity.y += delta * gravity

	# Using only the horizontal velocity, interpolate towards the input.
	var hvel = velocity
	hvel.y = 0

	var target = dir * MAX_SPEED
	var acceleration
	if dir.dot(hvel) > 0:
		acceleration = ACCELERATION
	else:
		acceleration = DECELERATION

	hvel = hvel.linear_interpolate(target, acceleration * delta)

	# Assign hvel's values back to velocity, and then move.
	velocity.x = hvel.x
	velocity.z = hvel.z
	velocity = move_and_slide(velocity, Vector3.UP)

	# Jumping code. is_on_floor() must come after move_and_slide().
	if is_on_floor() and Input.is_action_pressed("jump"):
		velocity.y = JUMP_SPEED

func _on_tcube_body_entered(body):
	if body == self:
		get_node("WinText").show()

extends KinematicBody

const MAX_SPEED = 3
const JUMP_SPEED = 5
const ACCELERATION = 2
const DECELERATION = 4

onready var gravity = -ProjectSettings.get_setting("physics/3d/default_gravity")
var velocity: Vector3

func _physics_process(delta):
	if Input.is_action_just_pressed("exit"):
		get_tree().quit()
	if Input.is_action_just_pressed("reset_position"):
		translation = Vector3(-3, 4, 8)

	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 = $Target/Camera.global_transform.basis
	var basis = cam_basis.rotated(cam_basis.x, -cam_basis.get_euler().x)
	dir = basis.xform(dir)

	# Limit the input to a length of 1. length_squared is faster to check.
	if dir.length_squared() > 1:
		dir /= dir.length()

	# Apply gravity.
	velocity.y += delta * gravity

	# Using only the horizontal velocity, interpolate towards the input.
	var hvel = velocity
	hvel.y = 0

	var target = dir * MAX_SPEED
	var acceleration
	if dir.dot(hvel) > 0:
		acceleration = ACCELERATION
	else:
		acceleration = DECELERATION

	hvel = hvel.linear_interpolate(target, acceleration * delta)

	# Assign hvel's values back to velocity, and then move.
	velocity.x = hvel.x
	velocity.z = hvel.z
	velocity = move_and_slide(velocity, Vector3.UP)

	# Jumping code. is_on_floor() must come after move_and_slide().
	if is_on_floor() and Input.is_action_pressed("jump"):
		velocity.y = JUMP_SPEED

func _on_tcube_body_entered(body):
	if body == self:
		get_node("WinText").show()


added sprite rotation for direction

added sprite rotation for direction

extends Area2D
#quick access to constnats
onready var CONST = get_node("/root/const")

const MOVESPEED_X = 100
const MOVESPEED_Y = 50

#quick access to animator
onready var anim = get_node("anim")
onready var sprites_attack = get_node("sprites_attack")
onready var sprites_move = get_node("sprites_move")

var curr_anim = ""
var current_sprite

func _fixed_process(delta):

	var next_anim = CONST.PLAYER_ANIM_IDLE
	current_sprite = sprites_move
	#gather inputs
	var move_left = Input.is_action_pressed("move_left")
	var move_right = Input.is_action_pressed("move_right")
	var move_up = Input.is_action_pressed("move_up")
	var move_down = Input.is_action_pressed("move_down")

	var pos = get_pos()
	var move_vector = Vector2()
	if (move_left):
		move_vector.x = -MOVESPEED_X
	if (move_right):
		move_vector.x = MOVESPEED_X
	if (move_up):
		move_vector.y = -MOVESPEED_Y
	if (move_down):
		move_vector.y = MOVESPEED_Y

	#integrate new position
	set_pos(pos + (move_vector * delta))

	#some movement involved
	if (move_vector.length_squared() != 0):
		next_anim = CONST.PLAYER_ANIM_WALK
		#flip sprite if direction change
		if (move_vector.x < 0 and move_left):
			current_sprite.set_scale(Vector2(-1.0, 1.0))
		elif (move_vector.x > 0 and move_right):
			current_sprite.set_scale(Vector2(1.0, 1.0))

	if (curr_anim != next_anim):
		curr_anim = next_anim
		anim.play(curr_anim)

func _ready():
	set_fixed_process(true)
	pass

extends Area2D
#quick access to constnats
onready var CONST = get_node("/root/const")

const MOVESPEED_X = 100
const MOVESPEED_Y = 50

#quick access to animator
onready var anim = get_node("anim")

var curr_anim = ""

func _fixed_process(delta):

	var next_anim = CONST.PLAYER_ANIM_IDLE
	#gather inputs
	var move_left = Input.is_action_pressed("move_left")
	var move_right = Input.is_action_pressed("move_right")
	var move_up = Input.is_action_pressed("move_up")
	var move_down = Input.is_action_pressed("move_down")

	var pos = get_pos()
	var move_vector = Vector2()
	if (move_left):
		move_vector.x = -MOVESPEED_X
	if (move_right):
		move_vector.x = MOVESPEED_X
	if (move_up):
		move_vector.y = -MOVESPEED_Y
	if (move_down):
		move_vector.y = MOVESPEED_Y

	#integrate new position
	set_pos(pos + (move_vector * delta))

	#some movement involved
	if (move_vector.length_squared() != 0):
		next_anim = CONST.PLAYER_ANIM_WALK

	if (curr_anim != next_anim):
		curr_anim = next_anim
		anim.play(curr_anim)

func _ready():
	set_fixed_process(true)
	pass


Fixed boss room break

Fixed boss room break


Change mouse cursor when mouse button is pressed/released

extends Node

var currentScene = null
var map = null
onready var cur1 = load("res://resources/ui/cursor1.png")
onready var cur2 = load("res://resources/ui/cursor2.png")

var PlayerName = "Niclas"
var MAP_WIDTH = 40
var MAP_HEIGHT = 30

func _ready():
	# print(currentScene, "hei")
	currentScene = get_tree().get_root().get_child(get_tree().get_root().get_child_count() -1)
	set_process_input(true)

func _input(event):
	if event.type == InputEvent.MOUSE_BUTTON:
		if event.is_pressed():
			Input.set_custom_mouse_cursor(cur2)
		else:
			Input.set_custom_mouse_cursor(cur1)

func set_scene(scene):
	currentScene.queue_free()
	var s = ResourceLoader.load(scene)
	currentScene = s.instance()
	get_tree().get_root().add_child(currentScene)

func set_map(mapname):
	var mappath = "res://maps/" + mapname
	if (File.new().file_exists(mappath)):
		map = mappath
		return true
	else:
		print("Map not found: ", mappath)
		return false

func get_map():
	return map

func get_player_name():
	return PlayerName

extends Node

var currentScene = null
var map = null

var PlayerName = "Niclas"
var MAP_WIDTH = 40
var MAP_HEIGHT = 30

func _ready():
	# print(currentScene, "hei")
	currentScene = get_tree().get_root().get_child(get_tree().get_root().get_child_count() -1)

func set_scene(scene):
	currentScene.queue_free()
	var s = ResourceLoader.load(scene)
	currentScene = s.instance()
	get_tree().get_root().add_child(currentScene)

func set_map(mapname):
	var mappath = "res://maps/" + mapname
	if (File.new().file_exists(mappath)):
		map = mappath
		return true
	else:
		print("Map not found: ", mappath)
		return false

func get_map():
	return map

func get_player_name():
	return PlayerName


better message

better message

extends Spatial

# Is there a better way to do this?
const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

# Block selection handling.
var offClick = false
var selectedBlocks = []

# Puzzle vars.
var puzzle
var puzzleLoaded = false
var blockNodes = {}

var puzzleScn

# Beam stuff.
const beamScn = preload( "res://blocks/block.scn" )
const Beam = preload("res://scripts/Blocks/Beam.gd")

# sounds
var samplePlayer = SamplePlayer.new()

func addPickledBlock(block):
	var b = block.toNode()

	# TODO  any special treatment for the wild blocks?
	# TODO  keep track of puzzle.lasers ? How to?
	blockNodes[block.blockPos] = b

	if puzzleLoaded:
		# keep pickled block
		puzzle.shape[block.blockPos] = block

		# keep track of puzzle.pairCounts
		var layer = calcBlockLayerVec(b.blockPos)
		if b.getBlockType() == 2:
			while puzzle.pairCount.size() <= layer:
				puzzle.pairCount.append(0)
			puzzle.puzzleLayers = puzzle.pairCount.size() - 1
			puzzle.pairCount[layer] += 0.5

	add_child(b)
	return b

func get_block(pos):
	if blockNodes.has(pos):
		return blockNodes[pos]
	else:
		return null

# unused key argument needed for the tween_complete signal
func remove_block(block=null, key=null):
	var block_node = blockNodes[block.blockPos]
	puzzle.shape[block_node.blockPos] = null

	if block_node == null:
		return

	blockNodes[block_node.blockPos] = null

	for child in block_node.get_children():
		block_node.remove_and_delete_child(child)
	remove_and_delete_child(block_node)

# Sets the puzzle for this GridMan.
func set_puzzle(puzz):
	# verify puzzle
	if puzz == null:
		print("INVALID PUZZLE")
		return

	# delete all current nodes
	if puzzle != null:
		for pos in puzzle.shape:
			remove_block(puzzle.shape[pos])
	puzzleLoaded = false
	#print( puzzDict.type() )
	print("This is puzz: ", puzz )

	puzzle = puzz

	# Load in the puzzle from dictionary
	#puzzle.fromDict(puzzDict)

		# # I can do my own counting!
	# needed for adding blocks in the editor
	for k in puzzle.shape:
		# Create a block node, add it to the tree
		addPickledBlock(puzzle.shape[k])
	puzzleLoaded = true

# Clears any selected blocks. WE SHOULD FIX THIS, THERE CAN ONLY BE ONE BLOCK SELECTED AT ANY ONE TIME, NO NEED FOR AN ARRAY!
func clearSelection():
	for bl in selectedBlocks:
		var blo = get_node( bl )
		blo.setSelected(false)
		blo.scaleTweenNode(1.0).start()
	selectedBlocks = []

# Add the selected block to the selected list. WE SHOULD FIX THIS, IT ONLY NEEDS TO STORE IT, NOT AN ARRAY!
func addSelected(bl):
	selectedBlocks.append(bl)

# Used for the multiplayer mode to force click a block on their side.
func forceClickBlock( pos ):
	blockNodes[pos].forceClick()

func clickBlock( name ):
	#now check if that was the second block we picked. If it was, we want to
	#unselect the blocks again
	if (offClick):
		offClick = false
		addSelected(name)
		clearSelection()
	else:
		offClick = true;
		addSelected(name)

# Calculates the layer that a block is on.
# COPY OF FUNCTION IN PUZZLEMAN, IS THERE A BETTER WAY TO DO THIS?!
func calcBlockLayer( x, y, z ):
	return max( max( abs( x ), abs( y ) ), abs( z ) )
func calcBlockLayerVec( pos ):
	return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

func beatenWithScore(othersScore):
	print( "BEATEN!" )
	var pauseMenu = get_tree().get_root().get_node( "Spatial" ).get_node( "Camera" ).pauseMenu
	pauseMenu.set_title("Game Over")
	pauseMenu.set_text("GAME OVER\nYou've been beaten with time: " + puzzleScn.formatTime(othersScore))
	pauseMenu.popup_centered()

func win():
	print( "GAME OVER!" )
	var pauseMenu = get_tree().get_root().get_node( "Spatial" ).get_node( "Camera" ).pauseMenu
	pauseMenu.set_title("Game Over")
	pauseMenu.set_text("GAME OVER\nYou win with time: " + puzzleScn.formatTime(get_parent().get_parent().time.val))
	pauseMenu.popup_centered()

# Handles keeping track of pairs being removed.
func popPair( pos ):
	var blayer = calcBlockLayerVec( pos )
	puzzle.pairCount[blayer] -= 1

	if( puzzle.pairCount[blayer] == 0 ):
		print("LAYER CLEARED")
		if blayer == 1:
			win()

		for b in puzzle.shape:
			if not ( puzzle.shape[b] == null ):
				if calcBlockLayerVec( b ) == blayer:
					if blockNodes[b].getBlockType() == BLOCK_LASER:
						blockNodes[b].forceActivate()

		# Fire beams.
		var beamNum = 0
		for l in range( puzzle.lasers.size() ):
			if calcBlockLayerVec( puzzle.lasers[l][0] ) == blayer:
				# Firin mah lazerz!
				var beam = beamScn.instance()

				beam.set_name( str(blayer) + "_beam_" + str(beamNum) )
				beamNum += 1
				beam.set_script( Beam )

				add_child( beam )
				beam.fire( puzzle.lasers[l][0], puzzle.lasers[l][1] )

				samplePlayer.play( "soundslikewillem_hitting_slinky" )

func _init():
	# Load sound
	samplePlayer.set_voice_count(10)
	samplePlayer.set_sample_library(ResourceLoader.load("new_samplelibrary.xml"))
	print("GridMan initialized")

func _ready():
	setupCam()

	puzzleScn = get_parent().get_parent()

func setupCam():
	var cam = get_tree().get_root().get_node( "Spatial/Camera" )
	if cam == null or puzzle == null:
		return
	var totalSize = ( puzzle.puzzleLayers * 2 + 1 )
	cam.distance.val = 4.5 * totalSize
	cam.distance.min_ = 3 * totalSize
	cam.distance.max_ = 10 * totalSize
	cam.recalculate_camera()

extends Spatial

# Is there a better way to do this?
const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

# Block selection handling.
var offClick = false
var selectedBlocks = []

# Puzzle vars.
var puzzle
var puzzleLoaded = false
var blockNodes = {}

var puzzleScn

# Beam stuff.
const beamScn = preload( "res://blocks/block.scn" )
const Beam = preload("res://scripts/Blocks/Beam.gd")

# sounds
var samplePlayer = SamplePlayer.new()

func addPickledBlock(block):
	var b = block.toNode()

	# TODO  any special treatment for the wild blocks?
	# TODO  keep track of puzzle.lasers ? How to?
	blockNodes[block.blockPos] = b

	if puzzleLoaded:
		# keep pickled block
		puzzle.shape[block.blockPos] = block

		# keep track of puzzle.pairCounts
		var layer = calcBlockLayerVec(b.blockPos)
		if b.getBlockType() == 2:
			while puzzle.pairCount.size() <= layer:
				puzzle.pairCount.append(0)
			puzzle.puzzleLayers = puzzle.pairCount.size() - 1
			puzzle.pairCount[layer] += 0.5

	add_child(b)
	return b

func get_block(pos):
	if blockNodes.has(pos):
		return blockNodes[pos]
	else:
		return null

# unused key argument needed for the tween_complete signal
func remove_block(block=null, key=null):
	var block_node = blockNodes[block.blockPos]
	puzzle.shape[block_node.blockPos] = null

	if block_node == null:
		return

	blockNodes[block_node.blockPos] = null

	for child in block_node.get_children():
		block_node.remove_and_delete_child(child)
	remove_and_delete_child(block_node)

# Sets the puzzle for this GridMan.
func set_puzzle(puzz):
	# verify puzzle
	if puzz == null:
		print("INVALID PUZZLE")
		return

	# delete all current nodes
	if puzzle != null:
		for pos in puzzle.shape:
			remove_block(puzzle.shape[pos])
	puzzleLoaded = false
	#print( puzzDict.type() )
	print("This is puzz: ", puzz )

	puzzle = puzz

	# Load in the puzzle from dictionary
	#puzzle.fromDict(puzzDict)

		# # I can do my own counting!
	# needed for adding blocks in the editor
	for k in puzzle.shape:
		# Create a block node, add it to the tree
		addPickledBlock(puzzle.shape[k])
	puzzleLoaded = true

# Clears any selected blocks. WE SHOULD FIX THIS, THERE CAN ONLY BE ONE BLOCK SELECTED AT ANY ONE TIME, NO NEED FOR AN ARRAY!
func clearSelection():
	for bl in selectedBlocks:
		var blo = get_node( bl )
		blo.setSelected(false)
		blo.scaleTweenNode(1.0).start()
	selectedBlocks = []

# Add the selected block to the selected list. WE SHOULD FIX THIS, IT ONLY NEEDS TO STORE IT, NOT AN ARRAY!
func addSelected(bl):
	selectedBlocks.append(bl)

# Used for the multiplayer mode to force click a block on their side.
func forceClickBlock( pos ):
	blockNodes[pos].forceClick()

func clickBlock( name ):
	#now check if that was the second block we picked. If it was, we want to
	#unselect the blocks again
	if (offClick):
		offClick = false
		addSelected(name)
		clearSelection()
	else:
		offClick = true;
		addSelected(name)

# Calculates the layer that a block is on.
# COPY OF FUNCTION IN PUZZLEMAN, IS THERE A BETTER WAY TO DO THIS?!
func calcBlockLayer( x, y, z ):
	return max( max( abs( x ), abs( y ) ), abs( z ) )
func calcBlockLayerVec( pos ):
	return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

func beatenWithScore(othersScore):
	print( "BEATEN!" )
	var pauseMenu = get_tree().get_root().get_node( "Spatial" ).get_node( "Camera" ).pauseMenu
	pauseMenu.set_text("GAME OVER\nYou've been beaten with time: " + puzzleScn.formatTime(othersScore))
	pauseMenu.popup_centered()

func win():
	print( "GAME OVER!" )
	var pauseMenu = get_tree().get_root().get_node( "Spatial" ).get_node( "Camera" ).pauseMenu
	pauseMenu.set_text("GAME OVER\nYou win with time: " + puzzleScn.formatTime(get_parent().get_parent().time.val))
	pauseMenu.popup_centered()

# Handles keeping track of pairs being removed.
func popPair( pos ):
	var blayer = calcBlockLayerVec( pos )
	puzzle.pairCount[blayer] -= 1

	if( puzzle.pairCount[blayer] == 0 ):
		print("LAYER CLEARED")
		if blayer == 1:
			win()

		for b in puzzle.shape:
			if not ( puzzle.shape[b] == null ):
				if calcBlockLayerVec( b ) == blayer:
					if blockNodes[b].getBlockType() == BLOCK_LASER:
						blockNodes[b].forceActivate()

		# Fire beams.
		var beamNum = 0
		for l in range( puzzle.lasers.size() ):
			if calcBlockLayerVec( puzzle.lasers[l][0] ) == blayer:
				# Firin mah lazerz!
				var beam = beamScn.instance()

				beam.set_name( str(blayer) + "_beam_" + str(beamNum) )
				beamNum += 1
				beam.set_script( Beam )

				add_child( beam )
				beam.fire( puzzle.lasers[l][0], puzzle.lasers[l][1] )

				samplePlayer.play( "soundslikewillem_hitting_slinky" )

func _init():
	# Load sound
	samplePlayer.set_voice_count(10)
	samplePlayer.set_sample_library(ResourceLoader.load("new_samplelibrary.xml"))
	print("GridMan initialized")

func _ready():
	setupCam()

	puzzleScn = get_parent().get_parent()

func setupCam():
	var cam = get_tree().get_root().get_node( "Spatial/Camera" )
	if cam == null or puzzle == null:
		return
	var totalSize = ( puzzle.puzzleLayers * 2 + 1 )
	cam.distance.val = 4.5 * totalSize
	cam.distance.min_ = 3 * totalSize
	cam.distance.max_ = 10 * totalSize
	cam.recalculate_camera()


forgot to check on floor before jumping

forgot to check on floor before jumping

extends KinematicBody2D

const GRAVITY_VEC = Vector2(0,900)
const FLOOR_NORMAL = Vector2(0,-1)
const SLOPE_SLIDE_STOP = 25.0
const MIN_ONAIR_TIME = 0.1
const WALK_SPEED = 250 # pixels/sec
const JUMP_SPEED = 480
const SIDING_CHANGE_SPEED = 10
const BULLET_VELOCITY = 1000
const SHOOT_TIME_SHOW_WEAPON = 0.2

var linear_vel = Vector2()
var onair_time = 0 #
var on_floor = false
var shoot_time=99999 #time since last shot

var anim=""

#cache the sprite here for fast access (we will set scale to flip it often)
onready var sprite = get_node("sprite")

func _fixed_process(delta):

	#increment counters

	onair_time+=delta
	shoot_time+=delta

	### MOVEMENT ###

	# Apply Gravity
	linear_vel += delta * GRAVITY_VEC
	# Move and Slide
	linear_vel = move_and_slide( linear_vel, FLOOR_NORMAL, SLOPE_SLIDE_STOP )
	# Detect Floor
	if (is_move_and_slide_on_floor()):
		onair_time=0

	on_floor = onair_time < MIN_ONAIR_TIME

	### CONTROL ###

	# Horizontal Movement
	var target_speed = 0
	if (Input.is_action_pressed("move_left")):
		target_speed += -1
	if (Input.is_action_pressed("move_right")):
		target_speed +=  1

	target_speed *= WALK_SPEED
	linear_vel.x = lerp( linear_vel.x, target_speed, 0.1 )

	# Jumping
	if (on_floor and Input.is_action_just_pressed("jump")):
		linear_vel.y=-JUMP_SPEED
		get_node("sound").play("jump")

	# Shooting

	if (Input.is_action_just_pressed("shoot")):

		var bullet = preload("res://bullet.tscn").instance()
		bullet.set_pos( get_node("sprite/bullet_shoot").get_global_pos() ) #use node for shoot position
		bullet.set_linear_velocity( Vector2( sprite.get_scale().x * BULLET_VELOCITY,0 ) )
		bullet.add_collision_exception_with(self) # don't want player to collide with bullet
		get_parent().add_child( bullet ) #don't want bullet to move with me, so add it as child of parent
		get_node("sound").play("shoot")
		shoot_time=0

	### ANIMATION ###

	var new_anim="idle"

	if (on_floor):
		if (linear_vel.x < -SIDING_CHANGE_SPEED):
			sprite.set_scale( Vector2( -1, 1 ) )
			new_anim="run"

		if (linear_vel.x > SIDING_CHANGE_SPEED):
			sprite.set_scale( Vector2( 1, 1 ) )
			new_anim="run"

	else:

		if (linear_vel.y < 0 ):
			new_anim="jumping"
		else:
			new_anim="falling"

	if (shoot_time < SHOOT_TIME_SHOW_WEAPON):
		new_anim+="_weapon"

	if (new_anim!=anim):
		anim=new_anim
		get_node("anim").play(anim)

func _ready():
	set_fixed_process(true)

extends KinematicBody2D

const GRAVITY_VEC = Vector2(0,900)
const FLOOR_NORMAL = Vector2(0,-1)
const SLOPE_SLIDE_STOP = 25.0
const MIN_ONAIR_TIME = 0.1
const WALK_SPEED = 250 # pixels/sec
const JUMP_SPEED = 480
const SIDING_CHANGE_SPEED = 10
const BULLET_VELOCITY = 1000
const SHOOT_TIME_SHOW_WEAPON = 0.2

var linear_vel = Vector2()
var onair_time = 0 #
var on_floor = false
var shoot_time=99999 #time since last shot

var anim=""

#cache the sprite here for fast access (we will set scale to flip it often)
onready var sprite = get_node("sprite")

func _fixed_process(delta):

	#increment counters

	onair_time+=delta
	shoot_time+=delta

	### MOVEMENT ###

	# Apply Gravity
	linear_vel += delta * GRAVITY_VEC
	# Move and Slide
	linear_vel = move_and_slide( linear_vel, FLOOR_NORMAL, SLOPE_SLIDE_STOP )
	# Detect Floor
	if (is_move_and_slide_on_floor()):
		onair_time=0

	on_floor = onair_time < MIN_ONAIR_TIME

	### CONTROL ###

	# Horizontal Movement
	var target_speed = 0
	if (Input.is_action_pressed("move_left")):
		target_speed += -1
	if (Input.is_action_pressed("move_right")):
		target_speed +=  1

	target_speed *= WALK_SPEED
	linear_vel.x = lerp( linear_vel.x, target_speed, 0.1 )

	# Jumping
	if (Input.is_action_just_pressed("jump")):
		linear_vel.y=-JUMP_SPEED
		get_node("sound").play("jump")

	# Shooting

	if (Input.is_action_just_pressed("shoot")):

		var bullet = preload("res://bullet.tscn").instance()
		bullet.set_pos( get_node("sprite/bullet_shoot").get_global_pos() ) #use node for shoot position
		bullet.set_linear_velocity( Vector2( sprite.get_scale().x * BULLET_VELOCITY,0 ) )
		bullet.add_collision_exception_with(self) # don't want player to collide with bullet
		get_parent().add_child( bullet ) #don't want bullet to move with me, so add it as child of parent
		get_node("sound").play("shoot")
		shoot_time=0

	### ANIMATION ###

	var new_anim="idle"

	if (on_floor):
		if (linear_vel.x < -SIDING_CHANGE_SPEED):
			sprite.set_scale( Vector2( -1, 1 ) )
			new_anim="run"

		if (linear_vel.x > SIDING_CHANGE_SPEED):
			sprite.set_scale( Vector2( 1, 1 ) )
			new_anim="run"

	else:

		if (linear_vel.y < 0 ):
			new_anim="jumping"
		else:
			new_anim="falling"

	if (shoot_time < SHOOT_TIME_SHOW_WEAPON):
		new_anim+="_weapon"

	if (new_anim!=anim):
		anim=new_anim
		get_node("anim").play(anim)

func _ready():
	set_fixed_process(true)


Shorter version

Shorter version

Works the same, but is shorter and more optimized (no _process function)

extends Node

var admob = null
var isTop = true
var ad_id = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX" [Replace with your Ad Unit ID and delete this message.]

func _ready():
	get_tree().connect("screen_resized",self,"update_size")
	if(Globals.has_singleton("AdMob")):
		admob = Globals.get_singleton("AdMob")
		admob.init(true, isTop, ad_id)
		admob.showBanner(true)

func update_size():
	if(admob != null):
		print(admob.getAdWidth(), ", ", admob.getAdHeight())
		admob.resize(isTop)

extends Node

var admob
var sizeOld
var isTop

func _ready():
	set_process(true)
	sizeOld		= OS.get_video_mode_size()
	isTop		= true
	if(Globals.has_singleton("AdMob")):
		admob		= Globals.get_singleton("AdMob")
		admob.init(true, isTop, "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX")	[Place your Ad Unit ID and delete this message.]
		admob.showBanner(true)
	else:
		admob	= null

func _process(delta):
	var size	= OS.get_video_mode_size()

	if( ((sizeOld.x - size.x) != 0) || ((sizeOld.y - size.y) != 0) ):
		sizeOld	= size
		if(null != admob):
			print(admob.getAdWidth(), ", ", admob.getAdHeight())
			admob.resize(isTop)


Removed redundant code in the kinematic 3D demo.

extends KinematicBody

# member variables here, example:
# var a=2
# var b="textvar"

var g = -9.8
var vel = Vector3()
const MAX_SPEED = 5
const JUMP_SPEED = 7
const ACCEL= 2
const DEACCEL= 4
const MAX_SLOPE_ANGLE = 30

func _fixed_process(delta):

	var dir = Vector3() #where does the player intend to walk to
	var cam_xform = get_node("target/camera").get_global_transform()

	if (Input.is_action_pressed("move_forward")):
		dir+=-cam_xform.basis[2]
	if (Input.is_action_pressed("move_backwards")):
		dir+=cam_xform.basis[2]
	if (Input.is_action_pressed("move_left")):
		dir+=-cam_xform.basis[0]
	if (Input.is_action_pressed("move_right")):
		dir+=cam_xform.basis[0]

	dir.y=0
	dir=dir.normalized()

	vel.y+=delta*g

	var hvel = vel
	hvel.y=0

	var target = dir*MAX_SPEED
	var accel
	if (dir.dot(hvel) >0):
		accel=ACCEL
	else:
		accel=DEACCEL

	hvel = hvel.linear_interpolate(target,accel*delta)

	vel.x=hvel.x;
	vel.z=hvel.z

	var motion = move(vel*delta)

	var on_floor = false
	var original_vel = vel

	var floor_velocity=Vector3()

	var attempts=4

	while(is_colliding() and attempts):
		var n=get_collision_normal()

		if ( rad2deg(acos(n.dot( Vector3(0,1,0)))) < MAX_SLOPE_ANGLE ):
				#if angle to the "up" vectors is < angle tolerance
				#char is on floor
				floor_velocity=get_collider_velocity()
				on_floor=true

		motion = n.slide(motion)
		vel = n.slide(vel)
		if (original_vel.dot(vel) > 0):
			#do not allow to slide towads the opposite direction we were coming from
			motion=move(motion)
			if (motion.length()<0.001):
				break
		attempts-=1

	if (on_floor and floor_velocity!=Vector3()):
			move(floor_velocity*delta)

	if (on_floor and Input.is_action_pressed("jump")):
		vel.y=JUMP_SPEED

	var crid = get_node("../elevator1").get_rid()
#	print(crid," : ",PS.body_get_state(crid,PS.BODY_STATE_TRANSFORM))

func _ready():
	# Initalization here
	set_fixed_process(true)
	pass

func _on_tcube_body_enter( body ):
	get_node("../ty").show()
	pass # replace with function body

extends KinematicBody

# member variables here, example:
# var a=2
# var b="textvar"

var g = -9.8
var vel = Vector3()
const MAX_SPEED = 5
const JUMP_SPEED = 7
const ACCEL= 2
const DEACCEL= 4
const MAX_SLOPE_ANGLE = 30

func _fixed_process(delta):

	var dir = Vector3() #where does the player intend to walk to
	var cam_xform = get_node("target/camera").get_global_transform()

	if (Input.is_action_pressed("move_forward")):
		dir+=-cam_xform.basis[2]
	if (Input.is_action_pressed("move_backwards")):
		dir+=cam_xform.basis[2]
	if (Input.is_action_pressed("move_left")):
		dir+=-cam_xform.basis[0]
	if (Input.is_action_pressed("move_right")):
		dir+=cam_xform.basis[0]

	dir.y=0
	dir=dir.normalized()

	vel.y+=delta*g

	var hvel = vel
	hvel.y=0

	var target = dir*MAX_SPEED
	var accel
	if (dir.dot(hvel) >0):
		accel=ACCEL
	else:
		accel=DEACCEL

	hvel = hvel.linear_interpolate(target,accel*delta)

	vel.x=hvel.x;
	vel.z=hvel.z

	var motion = vel*delta
	motion=move(vel*delta)

	var on_floor = false
	var original_vel = vel

	var floor_velocity=Vector3()

	var attempts=4

	while(is_colliding() and attempts):
		var n=get_collision_normal()

		if ( rad2deg(acos(n.dot( Vector3(0,1,0)))) < MAX_SLOPE_ANGLE ):
				#if angle to the "up" vectors is < angle tolerance
				#char is on floor
				floor_velocity=get_collider_velocity()
				on_floor=true

		motion = n.slide(motion)
		vel = n.slide(vel)
		if (original_vel.dot(vel) > 0):
			#do not allow to slide towads the opposite direction we were coming from
			motion=move(motion)
			if (motion.length()<0.001):
				break
		attempts-=1

	if (on_floor and floor_velocity!=Vector3()):
			move(floor_velocity*delta)

	if (on_floor and Input.is_action_pressed("jump")):
		vel.y=JUMP_SPEED

	var crid = get_node("../elevator1").get_rid()
#	print(crid," : ",PS.body_get_state(crid,PS.BODY_STATE_TRANSFORM))

func _ready():
	# Initalization here
	set_fixed_process(true)
	pass

func _on_tcube_body_enter( body ):
	get_node("../ty").show()
	pass # replace with function body


-renamed function to get object from instance id -added function to get list of tiles used

extends Node

var current_scene = null

func goto_scene(path):

	# This function will usually be called from a signal callback,
	# or some other function from the running scene.
	# Deleting the current scene at this point might be
	# a bad idea, because it may be inside of a callback or function of it.
	# The worst case will be a crash or unexpected behavior.

	# The way around this is deferring the load to a later time, when
	# it is ensured that no code from the current scene is running:

	call_deferred("_deferred_goto_scene",path)

func _deferred_goto_scene(path):

	# Immediately free the current scene,
	# there is no risk here.
	current_scene.free()

	# Load new scene
	var s = ResourceLoader.load(path)

	# Instance the new scene
	current_scene = s.instance()

	# Add it to the active scene, as child of root
	get_tree().get_root().add_child(current_scene)

func _ready():
	# Get the current scene, the first time.
	# it is always the last child of root,
	# after the autoloaded nodes.

	var root = get_tree().get_root()
	current_scene = root.get_child( root.get_child_count() -1 )

extends Node

var current_scene = null

func _deferred_goto_scene(path):

	# Immediately free the current scene,
        # there is no risk here.
	current_scene.free()

	# Load new scene
	var s = ResourceLoader.load(path)

	# Instance the new scene
	current_scene = s.instance()

	# Add it to the active scene, as child of root
	get_tree().get_root().add_child(current_scene)

func goto_scene(path):

	# This function will usually be called from a signal callback,
        # or some other function from the running scene.
	# Deleting the current scene at this point might be
        # a bad idea, because it may be inside of a callback or function of it.
	# The worst case will be a crash or unexpected behavior.

	# The way around this is deferring the load to a later time, when
        # it is ensured that no code from the current scene is running:

	call_deferred("_deferred_goto_scene",path)

func _ready():
	# Get the current scene, the first time.
	# it is always the last child of root,
	# after the autoloaded nodes.

	var root = get_tree().get_root()
	current_scene = root.get_child( root.get_child_count() -1 )


Agin check that the network is connected bfore trying to throw messages

# global working variables
var turn = Vector2( 0.0, 0.0 )            # the amount the mouse has turned
var mouseposlast = Input.get_mouse_pos()   # the mouses last position

# global tweakable parameters
var orbitrate = 10        # the rate the camera orbits the target when the mouse is moved
var active = true

func _ready():
	# Initalization here
	set_process_input(true)      # process user input events here

# called to handle a user input event
func _input(ev):
	if (not active):
		return
	# If the mouse has been moved
	if (ev.type==InputEvent.SCREEN_DRAG or (ev.type==InputEvent.MOUSE_MOTION and ev.button_mask == 1)):
		# calculate the delta change from the last mouse movement
		var mousedelta = (mouseposlast - ev.pos)
		# scale the mouse delta to a useful value
		turn = mousedelta / orbitrate
		# perform the rotation
		var currentTransform = get_transform().basis
		var dtime = get_process_delta_time()
		currentTransform = Matrix3( Vector3(0, 1, 0), PI * turn.x * dtime ) * currentTransform
		currentTransform = Matrix3( Vector3(1, 0, 0), PI * turn.y * dtime ) * currentTransform
		set_transform( Transform( currentTransform ) )
		var Network = Globals.get("Network")
		if (Network != null and Network.isNetwork):
			Network.sendTransform(currentTransform)

		# record the last position of the mousedelta

	if (ev.type==InputEvent.SCREEN_DRAG or ev.type==InputEvent.MOUSE_MOTION):
		mouseposlast = ev.pos
	# Android does not like this: Input.get_mouse_pos()

# global working variables
var turn = Vector2( 0.0, 0.0 )            # the amount the mouse has turned
var mouseposlast = Input.get_mouse_pos()   # the mouses last position

# global tweakable parameters
var orbitrate = 10        # the rate the camera orbits the target when the mouse is moved
var active = true

func _ready():
	# Initalization here
	set_process_input(true)      # process user input events here

# called to handle a user input event
func _input(ev):
	if (not active):
		return
	# If the mouse has been moved
	if (ev.type==InputEvent.SCREEN_DRAG or (ev.type==InputEvent.MOUSE_MOTION and ev.button_mask == 1)):
		# calculate the delta change from the last mouse movement
		var mousedelta = (mouseposlast - ev.pos)
		# scale the mouse delta to a useful value
		turn = mousedelta / orbitrate
		# perform the rotation
		var currentTransform = get_transform().basis
		var dtime = get_process_delta_time()
		currentTransform = Matrix3( Vector3(0, 1, 0), PI * turn.x * dtime ) * currentTransform
		currentTransform = Matrix3( Vector3(1, 0, 0), PI * turn.y * dtime ) * currentTransform
		set_transform( Transform( currentTransform ) )
		var Network = Globals.get("Network")
		if Network != null:
			Network.sendTransform(currentTransform)

		# record the last position of the mousedelta

	if (ev.type==InputEvent.SCREEN_DRAG or ev.type==InputEvent.MOUSE_MOTION):
		mouseposlast = ev.pos
	# Android does not like this: Input.get_mouse_pos()


slightly simpler

slightly simpler


quiet

quiet

extends "AbstractBlock.gd"

# Is there a better way to do this?
const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

var textureName

func setTexture(textureName="Red1"):
	var img = Image()
	self.textureName = textureName
	get_node("MeshInstance").set_material_override( load("res://glyph_materials/" + textureName + ".mtl") )
	return self

# Animate the removal of this block and its pair.
func popBlock( pairNode, justFly=false ):
	get_parent().samplePlayer.play("deraj_pop_sound_low")
	# fly away
	var tweenNode = newTweenNode()
	tweenNode.interpolate_method( self, "set_translation", \
		self.get_translation(), self.get_translation().normalized() * far_away_corner, \
		1, Tween.TRANS_CIRC, Tween.EASE_IN_OUT )

	# remove on animation end
	tweenNode.connect("tween_complete", self, "request_remove")
	tweenNode.start()
	# just one call to activate...
	if not justFly:
		pairNode.activate(true)
		get_parent().popPair( blockPos )

# THIS IS EVERYWHERE, ANY BETTER WAY TO HAVE FUNCTIONS BETWEEN SCRIPTS?
func calcBlockLayerVec( pos ):
	return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

# fly away only if self.pairName is selected
func activate(justFly = false):
	var gridMan = get_parent()
	if gridMan.selectedBlocks.size() > 0:
		var selBlock = gridMan.get_node( gridMan.selectedBlocks[0] )

		if selBlock.getBlockType() == BLOCK_WILD:
			if selBlock.textureName == textureName.substr( 0, selBlock.textureName.length() ):
				if calcBlockLayerVec( selBlock.blockPos ) == calcBlockLayerVec( blockPos ):
					gridMan.clearSelection()
					selBlock.popBlock()
					forceActivate()

					return

	var pairNode = pairActivate()
	if pairNode == null:
		return
	if pairNode.selected:
		popBlock( pairNode, justFly )

# Force the pair to activate.
func forceActivate():
	var pairNode = pairActivate()
	if pairNode == null:
		return

	popBlock( pairNode )

extends "AbstractBlock.gd"

# Is there a better way to do this?
const BLOCK_LASER	= 0
const BLOCK_WILD	= 1
const BLOCK_PAIR	= 2
const BLOCK_GOAL	= 3
const BLOCK_BLOCK   = 4

var textureName

func setTexture(textureName="Red1"):
	print(textureName)
	var img = Image()
	self.textureName = textureName
	get_node("MeshInstance").set_material_override( load("res://glyph_materials/" + textureName + ".mtl") )
	return self

# Animate the removal of this block and its pair.
func popBlock( pairNode, justFly=false ):
	get_parent().samplePlayer.play("deraj_pop_sound_low")
	# fly away
	var tweenNode = newTweenNode()
	tweenNode.interpolate_method( self, "set_translation", \
		self.get_translation(), self.get_translation().normalized() * far_away_corner, \
		1, Tween.TRANS_CIRC, Tween.EASE_IN_OUT )

	# remove on animation end
	tweenNode.connect("tween_complete", self, "request_remove")
	tweenNode.start()
	# just one call to activate...
	if not justFly:
		pairNode.activate(true)
		get_parent().popPair( blockPos )

# THIS IS EVERYWHERE, ANY BETTER WAY TO HAVE FUNCTIONS BETWEEN SCRIPTS?
func calcBlockLayerVec( pos ):
	return max( max( abs( pos.x ), abs( pos.y ) ), abs( pos.z ) )

# fly away only if self.pairName is selected
func activate(justFly = false):
	var gridMan = get_parent()
	if gridMan.selectedBlocks.size() > 0:
		var selBlock = gridMan.get_node( gridMan.selectedBlocks[0] )

		if selBlock.getBlockType() == BLOCK_WILD:
			print( selBlock.textureName )
			print( textureName.substr( 0, selBlock.textureName.length() ) )
			if selBlock.textureName == textureName.substr( 0, selBlock.textureName.length() ):
				if calcBlockLayerVec( selBlock.blockPos ) == calcBlockLayerVec( blockPos ):
					gridMan.clearSelection()
					selBlock.popBlock()
					forceActivate()

					return

	var pairNode = pairActivate()
	if pairNode == null:
		return
	if pairNode.selected:
		popBlock( pairNode, justFly )

# Force the pair to activate.
func forceActivate():
	var pairNode = pairActivate()
	if pairNode == null:
		return

	popBlock( pairNode )


Fixed double reporting of test suite results.

# Run as "godot -s main.gd"

extends SceneTree

const TEST_SOURCES = "res://tests/"
var BASE_TEST_CLASS = load(TEST_SOURCES + "base.gd")

func _init():
	var tests = find_tests_from_dir(TEST_SOURCES)
	run_tests(tests)
	quit()

func find_tests_from_dir(path):
	#print("Finding in " + path)
	var ret = []
	var dir = Directory.new()
	dir.open(path)
	dir.list_dir_begin()
	var file_name = dir.get_next()
	while file_name != "":
		var name = path + file_name
		if dir.current_is_dir():
			#print("Checking dir " + file_name + " [" +  file_name.right(file_name.length() - 6)+ "]")
			if file_name.right(file_name.length() - 6) == "_tests":
				for f in find_tests_from_dir(name + "/"):
					ret.append(f)
		else:
			var f = File.new()
			#print("Checking file " + name)
			if name.right(name.length() - 3) == ".gd" && f.file_exists(name):
				# print("TEST ADDED " + name)
				ret.append(name)
		file_name = dir.get_next()
	dir.list_dir_end()
	return ret

func run_tests(tests):
	var results = ResultCollector.new()
	for test in tests:
		var test_instance = create_test(test)
		if test_instance != null:
			run_test(test, test_instance, results)
	results._end()

func run_test(test_file, test_instance, results):
	# print("Running " + test_file)
	test_instance.filename = test_file.get_file()
	test_instance.filename = test_instance.filename.left(test_instance.filename.length() - 3)
	test_instance.run(results)

func create_test(test_file):
	if test_file.to_lower().find("/test_") < 0:
		# don't even report it.
		#print("ignoring " + test_file)
		return null
	var test_class = load(test_file)
	if test_class != null:
		var test_instance = test_class.new()
		if test_instance != null && test_instance extends BASE_TEST_CLASS:
			return test_instance
		print("*** SETUP ERROR: Not a valid test instance: " + test_file)
	else:
		print("*** SETUP ERROR: Could not load file " + test_file)
	return null

class ResultCollector:
	# This can be replaced or modified to allow for different kinds of output.
	# For example, a version could output the test results as a JSON object.

	# Results for all suites
	var suites = []

	# Current suite data
	var suite_name = null
	var test_stack = []
	var current_suite = null
	var current_test = null

	func start_suite(name):
		if suite_name != null:
			end_suite()
		suite_name = name

		# The start and end of the suite should be the suite-wide setup/teardown
		current_test = {
			"name": "<<class>>",
			"errors": []
		}
		test_stack = [ current_test ]
		current_suite = {
			"name": suite_name,
			"tests": [ current_test ],
			"error_count": 0
		}
		suites.append(current_suite)

	func end_suite():
		if suite_name == null:
			return
		if current_suite["error_count"] <= 0:
			print(suite_name + ": Success (" + str(current_suite["tests"].size()) + " tests)")
		else:
			print(suite_name + ": Failed (" + str(current_suite["error_count"]) + " errors, " + str(current_suite["tests"].size()) + " tests)")
		suite_name = null
		current_suite = null
		current_test = null

	func start_test(test_name):
		current_test = { "name": test_name, "errors": [] }
		test_stack.append(current_test)
		current_suite["tests"].append(current_test)

	func end_test():
		if test_stack.size() > 0:
			current_test = test_stack[test_stack.size() - 1]
			test_stack.pop_back()
		else:
			current_test = null

	func add_error(text):
		if current_suite == null || current_test == null:
			# We're outside the context of a suite or test.  Shouldn't happen.
			printerr("<<unknown test>> Failed: " + text)
		else:
			current_test["errors"].append(text)
			current_suite["error_count"] += 1
			printerr(suite_name + "::" + current_test["name"] + ": " + text)

		# It would be nice if we could capture the stack, so that the errors
		# could be assembled in a better form.  But, currently, Godot does not
		# support this.
		print_stack()

	func has_error():
		if current_test == null:
			return false
		return current_test["errors"].size() > 0

	func _end():
		# All test results are displayed during execution.
		# But we'll post a final summary
		var test_count = 0
		var error_count = 0
		var result
		for result in suites:
			test_count += result["tests"].size()
			error_count += result["error_count"]
		print("==============================")
		if error_count > 0:
			printerr("**** Test Failures ****")
		else:
			printerr("**** Success ****")
		printerr("Total Tests Ran: " + str(test_count))
		printerr("Total Errors: " + str(error_count))

# Run as "godot -s main.gd"

extends SceneTree

const TEST_SOURCES = "res://tests/"
var BASE_TEST_CLASS = load(TEST_SOURCES + "base.gd")

func _init():
	var tests = find_tests_from_dir(TEST_SOURCES)
	run_tests(tests)
	quit()

func find_tests_from_dir(path):
	#print("Finding in " + path)
	var ret = []
	var dir = Directory.new()
	dir.open(path)
	dir.list_dir_begin()
	var file_name = dir.get_next()
	while file_name != "":
		var name = path + file_name
		if dir.current_is_dir():
			#print("Checking dir " + file_name + " [" +  file_name.right(file_name.length() - 6)+ "]")
			if file_name.right(file_name.length() - 6) == "_tests":
				for f in find_tests_from_dir(name + "/"):
					ret.append(f)
		else:
			var f = File.new()
			#print("Checking file " + name)
			if name.right(name.length() - 3) == ".gd" && f.file_exists(name):
				#print("added " + name)
				ret.append(name)
		file_name = dir.get_next()
	dir.list_dir_end()
	return ret

func run_tests(tests):
	var results = ResultCollector.new()
	for test in tests:
		var test_instance = create_test(test)
		if test_instance != null:
			run_test(test, test_instance, results)
	results._end()

func run_test(test_file, test_instance, results):
	# print("Running " + test_file)
	test_instance.filename = test_file.get_file()
	test_instance.filename = test_instance.filename.left(test_instance.filename.length() - 3)
	test_instance.run(results)

func create_test(test_file):
	if test_file.to_lower().find("/test_") < 0:
		# don't even report it.
		#print("ignoring " + test_file)
		return null
	var test_class = load(test_file)
	if test_class != null:
		var test_instance = test_class.new()
		if test_instance != null && test_instance extends BASE_TEST_CLASS:
			return test_instance
		print("*** SETUP ERROR: Not a valid test instance: " + test_file)
	else:
		print("*** SETUP ERROR: Could not load file " + test_file)
	return null

class ResultCollector:
	# This can be replaced or modified to allow for different kinds of output.
	# For example, a version could output the test results as a JSON object.

	# Results for all suites
	var suites = []

	# Current suite data
	var suite_name = null
	var test_stack = []
	var current_suite = null
	var current_test = null

	func start_suite(name):
		if suite_name != null:
			end_suite()
		suite_name = name

		# The start and end of the suite should be the suite-wide setup/teardown
		current_test = {
			"name": "<<class>>",
			"errors": []
		}
		test_stack = [ current_test ]
		current_suite = {
			"name": suite_name,
			"tests": [ current_test ],
			"error_count": 0
		}
		suites.append(current_suite)

	func end_suite():
		if suite_name == null:
			return
		if current_suite["error_count"] <= 0:
			print(suite_name + ": Success (" + str(current_suite["tests"].size()) + " tests)")
			return
		print(suite_name + ": Failed (" + str(current_suite["error_count"]) + " errors, " + str(current_suite["tests"].size()) + " tests)")
		suite_name = null
		current_suite = null
		current_test = null

	func start_test(test_name):
		current_test = { "name": test_name, "errors": [] }
		test_stack.append(current_test)
		current_suite["tests"].append(current_test)

	func end_test():
		if test_stack.size() > 0:
			current_test = test_stack[test_stack.size() - 1]
			test_stack.pop_back()
		else:
			current_test = null

	func add_error(text):
		if current_suite == null || current_test == null:
			# We're outside the context of a suite or test.  Shouldn't happen.
			printerr("<<unknown test>> Failed: " + text)
		else:
			current_test["errors"].append(text)
			current_suite["error_count"] += 1
			printerr(suite_name + "::" + current_test["name"] + ": " + text)

		# It would be nice if we could capture the stack, so that the errors
		# could be assembled in a better form.  But, currently, Godot does not
		# support this.
		print_stack()

	func has_error():
		if current_test == null:
			return false
		return current_test["errors"].size() > 0

	func _end():
		# All test results are displayed during execution.
		# But we'll post a final summary
		var test_count = 0
		var error_count = 0
		var result
		for result in suites:
			test_count += result["tests"].size()
			error_count += result["error_count"]
		print("==============================")
		if error_count > 0:
			printerr("**** Test Failures ****")
		else:
			printerr("**** Success ****")
		printerr("Total Tests Ran: " + str(test_count))
		printerr("Total Errors: " + str(error_count))


Fixed hats for players

Fixed hats for players

extends "res://scripts/moving_object.gd"

var is_playing = false
var is_alive = true
var attack_range = 100
var attack_width = PI * 0.33
var attack_strength = 1
var blast

var target_cone
var target_cone_vector = [0, 0]
var target_cone_angle = 0.0

var panel

func _init(bag, player_id).(bag):
    self.bag = bag
    self.velocity = 200
    self.avatar = preload("res://scenes/player/player.xscn").instance()
    self.body_part_head = self.avatar.get_node('head')
    self.hat = self.body_part_head.get_node('hat')
    self.body_part_body = self.avatar.get_node('body')
    self.body_part_footer = self.avatar.get_node('footer')
    self.target_cone = self.avatar.get_node('attack_cone')
    self.animations = self.avatar.get_node('body_animations')
    self.blast = self.avatar.get_node('blast_animations')

    self.bind_gamepad(player_id)
    self.panel = self.bag.hud.bind_player_panel(player_id)
    self.hat.set_frame(player_id)

func bind_gamepad(id):
    var gamepad = self.bag.input.devices['pad' + str(id)]
    gamepad.register_handler(preload("res://scripts/input/handlers/player_enter_game_gamepad.gd").new(self.bag, self))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_move_axis.gd").new(self.bag, self, 0))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_move_axis.gd").new(self.bag, self, 1))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_cone_gamepad.gd").new(self.bag, self, 2))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_cone_gamepad.gd").new(self.bag, self, 3))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_attack_gamepad.gd").new(self.bag, self))

func bind_keyboard_and_mouse():
    var keyboard = self.bag.input.devices['keyboard']
    var mouse = self.bag.input.devices['mouse']
    keyboard.register_handler(preload("res://scripts/input/handlers/player_enter_game_keyboard.gd").new(self.bag, self))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 1, KEY_W, -1))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 1, KEY_S, 1))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 0, KEY_A, -1))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 0, KEY_D, 1))
    mouse.register_handler(preload("res://scripts/input/handlers/player_cone_mouse.gd").new(self.bag, self))
    mouse.register_handler(preload("res://scripts/input/handlers/player_attack_mouse.gd").new(self.bag, self))

func enter_game():
    self.is_playing = true
    self.spawn(self.bag.room_loader.get_spawn_position('initial'))
    self.panel.show()

func spawn(position):
    self.is_alive = true
    .spawn(position)

func die():
    self.is_alive = false
    .die()

func process(delta):
    self.adjust_attack_cone()

    .process(delta)

func modify_position(delta):
    .modify_position(delta)
    self.flip(self.target_cone_vector[0])
    if not self.animations.is_playing():
        self.animations.play('run')

    self.handle_items()

func handle_items():
    var items = self.bag.items.get_items_near_object(self)
    for item in items:
        print('ITEM _ FOUNDh')

func adjust_attack_cone():
    if abs(self.target_cone_vector[0]) < self.AXIS_THRESHOLD || abs(self.target_cone_vector[1]) < self.AXIS_THRESHOLD:
        return

    self.target_cone_angle = -atan2(self.target_cone_vector[1], self.target_cone_vector[0]) - PI/2
    self.target_cone.set_rot(self.target_cone_angle)

func attack():
    var enemies
    var random_attack = 'attack'+ str(1 + randi() % 2)

    if not self.animations.get_current_animation() == 'attack1' and not self.animations.get_current_animation() == 'attack2' :
        self.animations.play(random_attack);
        self.blast.play('blast')
    elif not self.animations.is_playing():
        if self.animations.get_current_animation() == 'attack1':
            self.animations.play('attack2')
        else:
            self.animations.play('attack1')
        self.blast.play('blast')

    enemies = self.bag.enemies.get_enemies_near_object(self, self.attack_range, self.target_cone_vector, self.attack_width)
    for enemy in enemies:
        enemy.recieve_damage(self.attack_strength)
        enemy.push_back(self)

func get_power(amount):
    self.attack_strength += amount
    if self.attack_range >= 16:
        self.die();

    self.hp -= amount
    self.max_hp -= amount

func get_fat(amount):
    self.hp += amount
    self.max_hp += amount

func check_colisions():
    return
    #print ('fff', self.avatar)

extends "res://scripts/moving_object.gd"

var is_playing = false
var is_alive = true
var attack_range = 100
var attack_width = PI * 0.33
var attack_strength = 1
var blast

var target_cone
var target_cone_vector = [0, 0]
var target_cone_angle = 0.0

var panel

func _init(bag, player_id).(bag):
    self.bag = bag
    self.velocity = 200
    self.avatar = preload("res://scenes/player/player.xscn").instance()
    self.body_part_head = self.avatar.get_node('head')
    self.hat = self.body_part_head.get_node('hat')
    self.body_part_body = self.avatar.get_node('body')
    self.body_part_footer = self.avatar.get_node('footer')
    self.target_cone = self.avatar.get_node('attack_cone')
    self.animations = self.avatar.get_node('body_animations')
    self.blast = self.avatar.get_node('blast_animations')

    self.bind_gamepad(player_id)
    self.panel = self.bag.hud.bind_player_panel(player_id)

func bind_gamepad(id):
    var gamepad = self.bag.input.devices['pad' + str(id)]
    gamepad.register_handler(preload("res://scripts/input/handlers/player_enter_game_gamepad.gd").new(self.bag, self))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_move_axis.gd").new(self.bag, self, 0))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_move_axis.gd").new(self.bag, self, 1))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_cone_gamepad.gd").new(self.bag, self, 2))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_cone_gamepad.gd").new(self.bag, self, 3))
    gamepad.register_handler(preload("res://scripts/input/handlers/player_attack_gamepad.gd").new(self.bag, self))

func bind_keyboard_and_mouse():
    var keyboard = self.bag.input.devices['keyboard']
    var mouse = self.bag.input.devices['mouse']
    keyboard.register_handler(preload("res://scripts/input/handlers/player_enter_game_keyboard.gd").new(self.bag, self))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 1, KEY_W, -1))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 1, KEY_S, 1))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 0, KEY_A, -1))
    keyboard.register_handler(preload("res://scripts/input/handlers/player_move_key.gd").new(self.bag, self, 0, KEY_D, 1))
    mouse.register_handler(preload("res://scripts/input/handlers/player_cone_mouse.gd").new(self.bag, self))
    mouse.register_handler(preload("res://scripts/input/handlers/player_attack_mouse.gd").new(self.bag, self))

func enter_game():
    self.is_playing = true
    self.spawn(self.bag.room_loader.get_spawn_position('initial'))
    self.panel.show()
    randomize()
    self.hat.set_frame(randi()%4)

func spawn(position):
    self.is_alive = true
    .spawn(position)

func die():
    self.is_alive = false
    .die()

func process(delta):
    self.adjust_attack_cone()

    .process(delta)

func modify_position(delta):
    .modify_position(delta)
    self.flip(self.target_cone_vector[0])
    if not self.animations.is_playing():
        self.animations.play('run')

    self.handle_items()

func handle_items():
    var items = self.bag.items.get_items_near_object(self)
    for item in items:
        print('ITEM _ FOUNDh')

func adjust_attack_cone():
    if abs(self.target_cone_vector[0]) < self.AXIS_THRESHOLD || abs(self.target_cone_vector[1]) < self.AXIS_THRESHOLD:
        return

    self.target_cone_angle = -atan2(self.target_cone_vector[1], self.target_cone_vector[0]) - PI/2
    self.target_cone.set_rot(self.target_cone_angle)

func attack():
    var enemies
    var random_attack = 'attack'+ str(1 + randi() % 2)

    if not self.animations.get_current_animation() == 'attack1' and not self.animations.get_current_animation() == 'attack2' :
        self.animations.play(random_attack);
        self.blast.play('blast')
    elif not self.animations.is_playing():
        if self.animations.get_current_animation() == 'attack1':
            self.animations.play('attack2')
        else:
            self.animations.play('attack1')
        self.blast.play('blast')

    enemies = self.bag.enemies.get_enemies_near_object(self, self.attack_range, self.target_cone_vector, self.attack_width)
    for enemy in enemies:
        enemy.recieve_damage(self.attack_strength)
        enemy.push_back(self)

func get_power(amount):
    self.attack_strength += amount
    if self.attack_range >= 16:
        self.die();

    self.hp -= amount
    self.max_hp -= amount

func get_fat(amount):
    self.hp += amount
    self.max_hp += amount

func check_colisions():
    return
    #print ('fff', self.avatar)


Joystick demo script cleanup

Joystick demo script cleanup

Removes a leftover variable and uses constants instead of magic numbers.

extends Node2D

# Joysticks demo, written by Dana Olson <dana@shineuponthee.com>
#
# This is a demo of joystick support, and doubles as a testing application
# inspired by and similar to jstest-gtk.
#
# Licensed under the MIT license

# Member variables
var joy_num
var cur_joy
var axis_value

const DEADZONE = 0.2

func _fixed_process(delta):
	# Get the joystick device number from the spinbox
	joy_num = get_node("joy_num").get_value()

	# Display the name of the joystick if we haven't already
	if joy_num != cur_joy:
		cur_joy = joy_num
		get_node("joy_name").set_text(Input.get_joy_name(joy_num))

	# Loop through the axes and show their current values
	for axis in range(JOY_ANALOG_0_X, JOY_AXIS_MAX):
		axis_value = Input.get_joy_axis(joy_num, axis)
		get_node("axis_prog" + str(axis)).set_value(100*axis_value)
		get_node("axis_val" + str(axis)).set_text(str(axis_value))
		# Show joystick direction indicators
		if (axis <= JOY_ANALOG_1_Y):
			if (abs(axis_value) < DEADZONE):
				get_node("diagram/axes/" + str(axis) + "+").hide()
				get_node("diagram/axes/" + str(axis) + "-").hide()
			elif (axis_value > 0):
				get_node("diagram/axes/" + str(axis) + "+").show()
			else:
				get_node("diagram/axes/" + str(axis) + "-").show()

	# Loop through the buttons and highlight the ones that are pressed
	for btn in range(JOY_BUTTON_0, JOY_BUTTON_MAX):
		if (Input.is_joy_button_pressed(joy_num, btn)):
			get_node("btn" + str(btn)).add_color_override("font_color", Color(1, 1, 1, 1))
			get_node("diagram/buttons/" + str(btn)).show()
		else:
			get_node("btn" + str(btn)).add_color_override("font_color", Color(0.2, 0.1, 0.3, 1))
			get_node("diagram/buttons/" + str(btn)).hide()

func _ready():
	set_fixed_process(true)
	Input.connect("joy_connection_changed", self, "_on_joy_connection_changed")

#Called whenever a joystick has been connected or disconnected.
func _on_joy_connection_changed(device_id, connected):
	if device_id == cur_joy:
		if connected:
			get_node("joy_name").set_text(Input.get_joy_name(device_id))
		else:
			get_node("joy_name").set_text("")

extends Node2D

# Joysticks demo, written by Dana Olson <dana@shineuponthee.com>
#
# This is a demo of joystick support, and doubles as a testing application
# inspired by and similar to jstest-gtk.
#
# Licensed under the MIT license

# Member variables
var joy_num
var cur_joy
var axis_value
var btn_state

const DEADZONE = 0.2

func _fixed_process(delta):
	# Get the joystick device number from the spinbox
	joy_num = get_node("joy_num").get_value()

	# Display the name of the joystick if we haven't already
	if joy_num != cur_joy:
		cur_joy = joy_num
		get_node("joy_name").set_text(Input.get_joy_name(joy_num))

	# Loop through the axes and show their current values
	for axis in range(0, 8):
		axis_value = Input.get_joy_axis(joy_num, axis)
		get_node("axis_prog" + str(axis)).set_value(100*axis_value)
		get_node("axis_val" + str(axis)).set_text(str(axis_value))
		if (axis < 4):
			if (abs(axis_value) < DEADZONE):
				get_node("diagram/axes/" + str(axis) + "+").hide()
				get_node("diagram/axes/" + str(axis) + "-").hide()
			elif (axis_value > 0):
				get_node("diagram/axes/" + str(axis) + "+").show()
			else:
				get_node("diagram/axes/" + str(axis) + "-").show()

	# Loop through the buttons and highlight the ones that are pressed
	for btn in range(0, 16):
		btn_state = 1
		if (Input.is_joy_button_pressed(joy_num, btn)):
			get_node("btn" + str(btn)).add_color_override("font_color", Color(1, 1, 1, 1))
			get_node("diagram/buttons/" + str(btn)).show()
		else:
			get_node("btn" + str(btn)).add_color_override("font_color", Color(0.2, 0.1, 0.3, 1))
			get_node("diagram/buttons/" + str(btn)).hide()

func _ready():
	set_fixed_process(true)
	Input.connect("joy_connection_changed", self, "_on_joy_connection_changed")

#Called whenever a joystick has been connected or disconnected.
func _on_joy_connection_changed(device_id, connected):
	if device_id == cur_joy:
		if connected:
			get_node("joy_name").set_text(Input.get_joy_name(device_id))
		else:
			get_node("joy_name").set_text("")


Platformer 2D: Simplify controller with proper is_on_floor usage

extends KinematicBody2D

const GRAVITY_VEC = Vector2(0, 900)
const FLOOR_NORMAL = Vector2(0, -1)
const SLOPE_SLIDE_STOP = 25.0
const WALK_SPEED = 250 # pixels/sec
const JUMP_SPEED = 480
const SIDING_CHANGE_SPEED = 10
const BULLET_VELOCITY = 1000
const SHOOT_TIME_SHOW_WEAPON = 0.2

var linear_vel = Vector2()
var on_floor = false
var shoot_time = 99999 # time since last shot

var anim = ""

# cache the sprite here for fast access (we will set scale to flip it often)
onready var sprite = $sprite

func _physics_process(delta):
	# Increment counters
	shoot_time += delta

	### MOVEMENT ###

	# Apply gravity
	linear_vel += delta * GRAVITY_VEC
	# Move and slide
	linear_vel = move_and_slide(linear_vel, FLOOR_NORMAL, SLOPE_SLIDE_STOP)
	# Detect if we are on floor - only works if called *after* move_and_slide
	var on_floor = is_on_floor()

	### CONTROL ###

	# Horizontal movement
	var target_speed = 0
	if Input.is_action_pressed("move_left"):
		target_speed -= 1
	if Input.is_action_pressed("move_right"):
		target_speed += 1

	target_speed *= WALK_SPEED
	linear_vel.x = lerp(linear_vel.x, target_speed, 0.1)

	# Jumping
	if on_floor and Input.is_action_just_pressed("jump"):
		linear_vel.y = -JUMP_SPEED
		$sound_jump.play()

	# Shooting
	if Input.is_action_just_pressed("shoot"):
		var bullet = preload("res://bullet.tscn").instance()
		bullet.position = $sprite/bullet_shoot.global_position # use node for shoot position
		bullet.linear_velocity = Vector2(sprite.scale.x * BULLET_VELOCITY, 0)
		bullet.add_collision_exception_with(self) # don't want player to collide with bullet
		get_parent().add_child(bullet) # don't want bullet to move with me, so add it as child of parent
		$sound_shoot.play()
		shoot_time = 0

	### ANIMATION ###

	var new_anim = "idle"

	if on_floor:
		if linear_vel.x < -SIDING_CHANGE_SPEED:
			sprite.scale.x = -1
			new_anim = "run"

		if linear_vel.x > SIDING_CHANGE_SPEED:
			sprite.scale.x = 1
			new_anim = "run"
	else:
		# We want the character to immediately change facing side when the player
		# tries to change direction, during air control.
		# This allows for example the player to shoot quickly left then right.
		if Input.is_action_pressed("move_left") and not Input.is_action_pressed("move_right"):
			sprite.scale.x = -1
		if Input.is_action_pressed("move_right") and not Input.is_action_pressed("move_left"):
			sprite.scale.x = 1

		if linear_vel.y < 0:
			new_anim = "jumping"
		else:
			new_anim = "falling"

	if shoot_time < SHOOT_TIME_SHOW_WEAPON:
		new_anim += "_weapon"

	if new_anim != anim:
		anim = new_anim
		$anim.play(anim)

extends KinematicBody2D

const GRAVITY_VEC = Vector2(0, 900)
const FLOOR_NORMAL = Vector2(0, -1)
const SLOPE_SLIDE_STOP = 25.0
const MIN_ONAIR_TIME = 0.1
const WALK_SPEED = 250 # pixels/sec
const JUMP_SPEED = 480
const SIDING_CHANGE_SPEED = 10
const BULLET_VELOCITY = 1000
const SHOOT_TIME_SHOW_WEAPON = 0.2

var linear_vel = Vector2()
var onair_time = 0 #
var on_floor = false
var shoot_time=99999 #time since last shot

var anim=""

#cache the sprite here for fast access (we will set scale to flip it often)
onready var sprite = $sprite

func _physics_process(delta):
	#increment counters

	onair_time += delta
	shoot_time += delta

	### MOVEMENT ###

	# Apply Gravity
	linear_vel += delta * GRAVITY_VEC
	# Move and Slide
	linear_vel = move_and_slide(linear_vel, FLOOR_NORMAL, SLOPE_SLIDE_STOP)
	# Detect Floor
	if is_on_floor():
		onair_time = 0

	on_floor = onair_time < MIN_ONAIR_TIME

	### CONTROL ###

	# Horizontal Movement
	var target_speed = 0
	if Input.is_action_pressed("move_left"):
		target_speed += -1
	if Input.is_action_pressed("move_right"):
		target_speed +=  1

	target_speed *= WALK_SPEED
	linear_vel.x = lerp(linear_vel.x, target_speed, 0.1)

	# Jumping
	if on_floor and Input.is_action_just_pressed("jump"):
		linear_vel.y = -JUMP_SPEED
		$sound_jump.play()

	# Shooting
	if Input.is_action_just_pressed("shoot"):
		var bullet = preload("res://bullet.tscn").instance()
		bullet.position = $sprite/bullet_shoot.global_position #use node for shoot position
		bullet.linear_velocity = Vector2(sprite.scale.x * BULLET_VELOCITY, 0)
		bullet.add_collision_exception_with(self) # don't want player to collide with bullet
		get_parent().add_child(bullet) #don't want bullet to move with me, so add it as child of parent
		$sound_shoot.play()
		shoot_time = 0

	### ANIMATION ###

	var new_anim = "idle"

	if on_floor:
		if linear_vel.x < -SIDING_CHANGE_SPEED:
			sprite.scale.x = -1
			new_anim = "run"

		if linear_vel.x > SIDING_CHANGE_SPEED:
			sprite.scale.x = 1
			new_anim = "run"
	else:
		# We want the character to immediately change facing side when the player
		# tries to change direction, during air control.
		# This allows for example the player to shoot quickly left then right.
		if Input.is_action_pressed("move_left") and not Input.is_action_pressed("move_right"):
			sprite.scale.x = -1
		if Input.is_action_pressed("move_right") and not Input.is_action_pressed("move_left"):
			sprite.scale.x = 1

		if linear_vel.y < 0:
			new_anim = "jumping"
		else:
			new_anim = "falling"

	if shoot_time < SHOOT_TIME_SHOW_WEAPON:
		new_anim += "_weapon"

	if new_anim != anim:
		anim = new_anim
		$anim.play(anim)


Changed how the player moves.

Changed how the player moves.

extends Node2D

# member variables here, example:
# var a=2
# var b="textvar"

var jump_cd = false
signal moved(pos)
signal jump
signal attack
var attacking = false
var sprinting = false
var vel = Vector2(0, 0)
var cur_vel = 0
var max_vel = 150
var sprint_factor = 1.5
var rot_spd = 5
var root = null
var anim = null

func _ready():
	self.set_process(true)
	self.set_process_input(true)
	root = get_tree().get_root().get_node("Game")
	anim = get_node("BodyAnimation")

func _draw():
	pass

func _input(event):
	if event.is_action_pressed("MOVE_UP"):
		vel.y = vel.y + max_vel
	elif event.is_action_released("MOVE_UP"):
		vel.y = vel.y - max_vel
	if event.is_action_pressed("MOVE_DOWN"):
		vel.y = vel.y - max_vel
	elif event.is_action_released("MOVE_DOWN"):
		vel.y = vel.y + max_vel
	if event.is_action_pressed("MOVE_LEFT"):
		vel.x = vel.x + max_vel
	elif event.is_action_released("MOVE_LEFT"):
		vel.x = vel.x - max_vel
	if event.is_action_pressed("MOVE_RIGHT"):
		vel.x = vel.x - max_vel
	elif event.is_action_released("MOVE_RIGHT"):
		vel.x = vel.x + max_vel

func _process(delta):
	if Input.is_action_pressed("ATTACK"):
		if not attacking:
			emit_signal("attack")
			attacking = true
	else:
		attacking = false

	if Input.is_action_pressed("MOVE_JUMP"):
		self.jump()

	if root:
		var r = get_angle_to(root.get_global_mouse_pos()) * (rot_spd * delta)
		rotate(r)

	if Input.is_action_pressed("SPRINT"):
		# self.move_and_slide(vel * 75 * delta)
		self.move(vel * 1.5 * delta)
	else:
		print(vel.rotated(get_rot()), vel)
		# self.move_and_slide(vel * 50 * delta)
		self.move(vel.rotated(get_rot()) * delta)

	self.emit_signal("moved", self.get_pos())
	if anim:
		if vel.x > 0.0 or vel.x < 0.0 or vel.y > 0.0 or vel.y < 0.0:
			if not anim.is_playing():
				anim.play("Walk")
			else:
				if Input.is_action_pressed("SPRINT"):
					anim.set_speed(sprint_factor)
				else:
					anim.set_speed(1)
				# print("Starting")
		else:
			if anim.is_playing():
				# print("Stopping")
				anim.stop(true)

func jump():
	self.emit_signal("jump")
	self.emit_signal("moved", self.get_pos())

extends Node2D

# member variables here, example:
# var a=2
# var b="textvar"

var jump_cd = false
signal moved(pos)
signal jump
signal attack
var attacking = false
var sprinting = false
var vel = Vector2(0, 0)
var cur_vel = 0
var max_vel = 150
var sprint_factor = 1.5
var rot_spd = 5
var root = null
var anim = null

func _ready():
	self.set_process(true)
	self.set_process_input(true)
	root = get_tree().get_root().get_node("Game")
	anim = get_node("BodyAnimation")

func _draw():
	pass

func _input(event):
	if event.is_action_pressed("MOVE_UP"):
		vel.y = vel.y - max_vel
	elif event.is_action_released("MOVE_UP"):
		vel.y = vel.y + max_vel
	if event.is_action_pressed("MOVE_DOWN"):
		vel.y = vel.y + max_vel
	elif event.is_action_released("MOVE_DOWN"):
		vel.y = vel.y - max_vel
	if event.is_action_pressed("MOVE_LEFT"):
		vel.x = vel.x - max_vel
	elif event.is_action_released("MOVE_LEFT"):
		vel.x = vel.x + max_vel
	if event.is_action_pressed("MOVE_RIGHT"):
		vel.x = vel.x + max_vel
	elif event.is_action_released("MOVE_RIGHT"):
		vel.x = vel.x - max_vel

func _process(delta):
	if Input.is_action_pressed("ATTACK"):
		if not attacking:
			emit_signal("attack")
			attacking = true
	else:
		attacking = false

	if Input.is_action_pressed("MOVE_JUMP"):
		self.jump()

	if root:
		var r = get_angle_to(root.get_global_mouse_pos()) * (rot_spd * delta)
		rotate(r)

	if Input.is_action_pressed("SPRINT"):
		# self.move_and_slide(vel * 75 * delta)
		self.move(vel * 1.5 * delta)
	else:
		# self.move_and_slide(vel * 50 * delta)
		self.move(vel * delta)

	self.emit_signal("moved", self.get_pos())
	if anim:
		if vel.x > 0.0 or vel.x < 0.0 or vel.y > 0.0 or vel.y < 0.0:
			if not anim.is_playing():
				anim.play("Walk")
			else:
				if Input.is_action_pressed("SPRINT"):
					anim.set_speed(sprint_factor)
				else:
					anim.set_speed(1)
				# print("Starting")
		else:
			if anim.is_playing():
				# print("Stopping")
				anim.stop(true)

func jump():
	self.emit_signal("jump")
	self.emit_signal("moved", self.get_pos())


Fix bug that could prevent cubio from saving the princess

extends KinematicBody

# Member variables
var g = -9.8
var vel = Vector3()
const MAX_SPEED = 5
const JUMP_SPEED = 7
const ACCEL= 2
const DEACCEL= 4
const MAX_SLOPE_ANGLE = 30

func _fixed_process(delta):
	var dir = Vector3() # Where does the player intend to walk to
	var cam_xform = get_node("target/camera").get_global_transform()

	if (Input.is_action_pressed("move_forward")):
		dir += -cam_xform.basis[2]
	if (Input.is_action_pressed("move_backwards")):
		dir += cam_xform.basis[2]
	if (Input.is_action_pressed("move_left")):
		dir += -cam_xform.basis[0]
	if (Input.is_action_pressed("move_right")):
		dir += cam_xform.basis[0]

	dir.y = 0
	dir = dir.normalized()

	vel.y += delta*g

	var hvel = vel
	hvel.y = 0

	var target = dir*MAX_SPEED
	var accel
	if (dir.dot(hvel) > 0):
		accel = ACCEL
	else:
		accel = DEACCEL

	hvel = hvel.linear_interpolate(target, accel*delta)

	vel.x = hvel.x
	vel.z = hvel.z

	var motion = move(vel*delta)

	var on_floor = false
	var original_vel = vel
	var floor_velocity = Vector3()
	var attempts = 4

	while(is_colliding() and attempts):
		var n = get_collision_normal()

		if (rad2deg(acos(n.dot(Vector3(0, 1, 0)))) < MAX_SLOPE_ANGLE):
				# If angle to the "up" vectors is < angle tolerance,
				# char is on floor
				floor_velocity = get_collider_velocity()
				on_floor = true

		motion = n.slide(motion)
		vel = n.slide(vel)
		if (original_vel.dot(vel) > 0):
			# Do not allow to slide towads the opposite direction we were coming from
			motion=move(motion)
			if (motion.length() < 0.001):
				break
		attempts -= 1

	if (on_floor and floor_velocity != Vector3()):
		move(floor_velocity*delta)

	if (on_floor and Input.is_action_pressed("jump")):
		vel.y = JUMP_SPEED

	var crid = get_node("../elevator1").get_rid()

func _ready():
	set_fixed_process(true)

func _on_tcube_body_enter(body):
	if (body == self):
		get_node("../ty").show()

extends KinematicBody

# Member variables
var g = -9.8
var vel = Vector3()
const MAX_SPEED = 5
const JUMP_SPEED = 7
const ACCEL= 2
const DEACCEL= 4
const MAX_SLOPE_ANGLE = 30

func _fixed_process(delta):
	var dir = Vector3() # Where does the player intend to walk to
	var cam_xform = get_node("target/camera").get_global_transform()

	if (Input.is_action_pressed("move_forward")):
		dir += -cam_xform.basis[2]
	if (Input.is_action_pressed("move_backwards")):
		dir += cam_xform.basis[2]
	if (Input.is_action_pressed("move_left")):
		dir += -cam_xform.basis[0]
	if (Input.is_action_pressed("move_right")):
		dir += cam_xform.basis[0]

	dir.y = 0
	dir = dir.normalized()

	vel.y += delta*g

	var hvel = vel
	hvel.y = 0

	var target = dir*MAX_SPEED
	var accel
	if (dir.dot(hvel) > 0):
		accel = ACCEL
	else:
		accel = DEACCEL

	hvel = hvel.linear_interpolate(target, accel*delta)

	vel.x = hvel.x
	vel.z = hvel.z

	var motion = move(vel*delta)

	var on_floor = false
	var original_vel = vel
	var floor_velocity = Vector3()
	var attempts = 4

	while(is_colliding() and attempts):
		var n = get_collision_normal()

		if (rad2deg(acos(n.dot(Vector3(0, 1, 0)))) < MAX_SLOPE_ANGLE):
				# If angle to the "up" vectors is < angle tolerance,
				# char is on floor
				floor_velocity = get_collider_velocity()
				on_floor = true

		motion = n.slide(motion)
		vel = n.slide(vel)
		if (original_vel.dot(vel) > 0):
			# Do not allow to slide towads the opposite direction we were coming from
			motion=move(motion)
			if (motion.length() < 0.001):
				break
		attempts -= 1

	if (on_floor and floor_velocity != Vector3()):
		move(floor_velocity*delta)

	if (on_floor and Input.is_action_pressed("jump")):
		vel.y = JUMP_SPEED

	var crid = get_node("../elevator1").get_rid()

func _ready():
	set_fixed_process(true)

func _on_tcube_body_enter(body):
	get_node("../ty").show()