Initial commit
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
extends Node3D
|
||||
class_name LevelGenerator
|
||||
|
||||
var levelGrid: Array[Array]
|
||||
@export var gridSize: int = 250
|
||||
|
||||
var spawnableRooms: Array[RoomData]
|
||||
var biomes: Array[Biome]
|
||||
var rng := RandomNumberGenerator.new()
|
||||
|
||||
func _ready() -> void:
|
||||
initGrid()
|
||||
|
||||
var spaceshipRoomList := RoomListSpaceship.new() # Have something choose the map in this part later
|
||||
spawnableRooms = spaceshipRoomList.rooms
|
||||
|
||||
var temp: Array[DoorPosition]
|
||||
# Generate the level
|
||||
temp = spawnRoom(spawnableRooms[0],Vector2i(30,30),0,true)
|
||||
for x in temp:
|
||||
spawnRoomAtDoor(spawnableRooms,x)
|
||||
#spawnRoomAtDoor(spawnableRooms[0],temp[x])
|
||||
printLevelGrid()
|
||||
|
||||
#Utility
|
||||
func initGrid() -> void:
|
||||
for x in gridSize:
|
||||
var newRow: Array
|
||||
levelGrid.push_back(newRow)
|
||||
for y in gridSize:
|
||||
var newCell := GridCell.new()
|
||||
levelGrid[x].push_back(newCell)
|
||||
func addGridCells(cell1: GridCell,cell2: GridCell) -> GridCell:
|
||||
var returnCell: GridCell = GridCell.new()
|
||||
returnCell.spaceTaken = cell1.spaceTaken or cell2.spaceTaken
|
||||
returnCell.door = cell2.door
|
||||
returnCell.doorOrientation = cell2.doorOrientation
|
||||
returnCell.biome = cell1.biome
|
||||
return returnCell
|
||||
func addArrays2D(array1: Array[Array], array2: Array[Array], arr2pos: Vector2i = Vector2i(0,0)) -> void:
|
||||
if array1.size() <= (arr2pos.x) + array2.size(): return
|
||||
if array1[arr2pos.y].size() <= (arr2pos.y) + array2[0].size(): return
|
||||
for x in array2.size():
|
||||
for y in array2[x].size():
|
||||
array1[x+arr2pos.x][y+arr2pos.y] = addGridCells(array1[x+arr2pos.x][y+arr2pos.y],array2[x][y])
|
||||
func checkOverlapArrays2D(array1: Array[Array], array2: Array[Array], arr2pos: Vector2i = Vector2i(0,0)) -> bool:
|
||||
if array1.size() <= (arr2pos.x) + array2.size(): return true
|
||||
if array1[arr2pos.y].size() <= (arr2pos.y) + array2[0].size(): return true
|
||||
for x in array2.size():
|
||||
for y in array2[x].size():
|
||||
if array1[x+arr2pos.x][y+arr2pos.y].spaceTaken and array2[x][y].spaceTaken: return true
|
||||
return false
|
||||
func rotateArray2D(array: Array[Array], numberOfRotationsBy90Degrees: int) -> void:
|
||||
var size: int = array.size()
|
||||
var layerCount: int = size/2
|
||||
|
||||
for x in numberOfRotationsBy90Degrees%4:
|
||||
for layer in layerCount:
|
||||
var first: int = layer
|
||||
var last: int = size - first - 1
|
||||
|
||||
for element in range(first, last):
|
||||
var offset = element - first
|
||||
|
||||
var top = array[first][element]
|
||||
var right = array[element][last]
|
||||
var bot = array[last][last-offset]
|
||||
var left = array[last-offset][first]
|
||||
|
||||
array[element][last] = top
|
||||
array[last][last-offset] = right
|
||||
array[last-offset][first] = bot
|
||||
array[first][element] = left
|
||||
func getDoorPosition(cell: GridCell, GridCellPosition: Vector2i) -> DoorPosition:
|
||||
if !cell.door:
|
||||
print("Tried to get door at cell that isnt a door")
|
||||
return null
|
||||
var returnDoorPosition := DoorPosition.new()
|
||||
returnDoorPosition.pos = GridCellPosition
|
||||
returnDoorPosition.orientation = cell.doorOrientation
|
||||
return returnDoorPosition
|
||||
func addObject(AddedObject:PackedScene, Parent: Node3D, Position: Vector3, Rotation: Vector3= Vector3(0,0,0)):
|
||||
if !AddedObject:
|
||||
print("tried to add object but packed scene is null")
|
||||
return
|
||||
var obj = AddedObject.instantiate()
|
||||
Parent.add_child(obj)
|
||||
obj.position = Position
|
||||
obj.rotation = Rotation
|
||||
return obj
|
||||
|
||||
#Spawning Rooms
|
||||
func rotateRoomData(roomData: RoomData, numberOfRotationsBy90Degrees: int) -> void:
|
||||
rotateArray2D(roomData.roomGrid,numberOfRotationsBy90Degrees)
|
||||
roomData.rotations = wrapi(roomData.rotations + numberOfRotationsBy90Degrees,0,4)
|
||||
for door in roomData.doorPositions:
|
||||
door.rotatePosRight(roomData.roomGrid.size(),numberOfRotationsBy90Degrees)
|
||||
func spawnRoom(roomDataInput: RoomData,pos: Vector2i,numberOfRotationsBy90Degrees: int = 0, centered: bool = false) -> Array[DoorPosition]: #Pos corresponds to the upper left corner of the room immage
|
||||
var roomData: RoomData = roomDataInput.duplicateRoom()
|
||||
var roomScene: PackedScene = load(roomData.roomSceneRef)
|
||||
rotateRoomData(roomData,numberOfRotationsBy90Degrees)
|
||||
var roomGrid := roomData.roomGrid
|
||||
var doorPositions: Array[DoorPosition] = roomData.doorPositions
|
||||
if centered:
|
||||
pos = Vector2i(pos.x-(roomGrid.size()/2),pos.y-(roomGrid[0].size()/2))
|
||||
|
||||
addArrays2D(levelGrid,roomGrid,pos)
|
||||
addObject(roomScene,self,Vector3(pos.x+(roomGrid.size()/2),0,pos.y+(roomGrid[0].size()/2)),Vector3(0,(roomData.rotations%4)*PI/2,0))
|
||||
for door in doorPositions:
|
||||
door.pos = pos + door.pos
|
||||
|
||||
return doorPositions
|
||||
func getDoorFromRoom(roomData: RoomData,index: int) -> DoorPosition:
|
||||
return roomData.doorPositions[index % roomData.doorPositions.size()]
|
||||
func putRoomAtDoor(roomData: RoomData, door: DoorPosition,spawnDoorIndex: int) -> Array: ##Return array contains roomData, spawn Pos in that order
|
||||
#Init Values:
|
||||
var spawnDoor: DoorPosition = getDoorFromRoom(roomData,spawnDoorIndex) #Which door from the spawned room connects to the exiting room
|
||||
var doorOrientationDifference : int = wrapi(spawnDoor.orientation - door.orientation,0,4) #Difference in orinet. between spawned and existing room
|
||||
var numberOfRoomRotations: int = 0 #How many rotations are needed to make spawned rooms spawn door face the existing door
|
||||
var spawnPos: Vector2i
|
||||
var doorOffset: Vector2i #Offset by 1 space so the doors are next to eachother and not inside eachoter
|
||||
|
||||
#Find number of rotations and then rotate the room
|
||||
if !doorOrientationDifference == 2:
|
||||
if doorOrientationDifference == 1:
|
||||
numberOfRoomRotations = 3
|
||||
if doorOrientationDifference == 0:
|
||||
numberOfRoomRotations = 2
|
||||
if doorOrientationDifference == 3:
|
||||
numberOfRoomRotations = 1
|
||||
rotateRoomData(roomData,numberOfRoomRotations)
|
||||
|
||||
#Get new values for spawnDoor and set door offset
|
||||
spawnDoor = getDoorFromRoom(roomData,spawnDoorIndex)
|
||||
match spawnDoor.orientation:
|
||||
0: doorOffset = Vector2i(0,-1)
|
||||
1: doorOffset = Vector2i(1,0)
|
||||
2: doorOffset = Vector2i(0,1)
|
||||
3: doorOffset = Vector2i(-1,0)
|
||||
|
||||
#Set spawn pos and return values
|
||||
spawnPos = door.pos - spawnDoor.pos + doorOffset
|
||||
var returnArray: Array = [roomData,spawnPos]
|
||||
return returnArray
|
||||
func spawnRoomAtDoor(roomDataInput: Array[RoomData], door: DoorPosition) -> void:
|
||||
var roomData: RoomData = null
|
||||
var spawnDoorIndex: int = -1
|
||||
#Choose the room to use
|
||||
var rooms: Array[RoomData] = roomDataInput.duplicate()
|
||||
rooms.shuffle()
|
||||
for room in rooms:
|
||||
#Check if room has allready been found
|
||||
if roomData and spawnDoorIndex != -1:
|
||||
break
|
||||
|
||||
#Randomise door checking order
|
||||
var doorIndices: Array[int]
|
||||
for x in room.doorPositions.size():
|
||||
doorIndices.push_back(x)
|
||||
doorIndices.shuffle()
|
||||
|
||||
#Check if doorIndex fits and assign roomData and spawnDoorIndex if it does
|
||||
for doorIndex in doorIndices:
|
||||
if checkIfRoomFits(room,door,doorIndex):
|
||||
roomData = room.duplicateRoom()
|
||||
spawnDoorIndex = doorIndex
|
||||
break
|
||||
|
||||
#Check if a room has been found
|
||||
if !roomData or spawnDoorIndex == -1: return
|
||||
|
||||
#Get Spawn Info and spawn room
|
||||
var spawnInfo: Array = putRoomAtDoor(roomData,door,spawnDoorIndex)
|
||||
spawnRoom(spawnInfo[0],spawnInfo[1])
|
||||
func checkIfRoomFits(roomDataInput: RoomData,door: DoorPosition,spawnDoorIndex: int) -> bool:
|
||||
var roomData: RoomData = roomDataInput.duplicateRoom()
|
||||
var spawnInfo: Array = putRoomAtDoor(roomData,door,spawnDoorIndex)
|
||||
if checkOverlapArrays2D(levelGrid,spawnInfo[0].roomGrid,spawnInfo[1]):
|
||||
return false
|
||||
else:
|
||||
return true
|
||||
|
||||
#Debug Functions
|
||||
func printLevelGrid() -> void:
|
||||
for x in levelGrid.size():
|
||||
for y in levelGrid[x].size():
|
||||
if levelGrid[x][y].spaceTaken:
|
||||
debugCubeAtPos(Vector2(x,y))
|
||||
func debugCubeAtPos(pos: Vector2):
|
||||
var debugCube: PackedScene = preload("res://test/debugCube.tscn")
|
||||
addObject(debugCube,self,Vector3(pos.x+0.5,0,pos.y+0.5))
|
||||
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cub0eem47ktoj"
|
||||
path="res://.godot/imported/Astroid.png-61b3d1f1c9788d7a24adef66ed4ac92c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/2D/SteeringMinigame/Astroid.png"
|
||||
dest_files=["res://.godot/imported/Astroid.png-61b3d1f1c9788d7a24adef66ed4ac92c.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@@ -0,0 +1,192 @@
|
||||
extends Control
|
||||
class_name Main
|
||||
|
||||
var paused = false
|
||||
|
||||
@onready var start_btn = $Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer4/VBoxContainer3/Start
|
||||
@onready var disconnect_btn = $Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer4/VBoxContainer3/Disconnect
|
||||
@onready var name_edit = $Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer4/VBoxContainer2/NameEdit
|
||||
@onready var disconnectDialog = $Dialogs/DisconnectDialog
|
||||
|
||||
@onready var mapsParent: Node3D = $Maps
|
||||
@onready var playersParent: Node3D = $Players
|
||||
|
||||
var peer = WebSocketMultiplayerPeer.new()
|
||||
var lobby: PackedScene = preload("res://Maps/Lobby/Lobby.tscn")
|
||||
|
||||
var player: PackedScene = preload("res://actors/Player/player_character.tscn")
|
||||
|
||||
var mic_capture : AudioEffectOpusChunked
|
||||
var audio_stats : Dictionary[int, Array]# id->[last_number, packetsreceived, packetslost]
|
||||
var packets_sent: int = 0
|
||||
func _init():
|
||||
peer.supported_protocols = ["ludus"]
|
||||
Steamworks.initialize()
|
||||
|
||||
func _ready():
|
||||
var mic_bus = AudioServer.get_bus_index("Mic")
|
||||
mic_capture = AudioServer.get_bus_effect(mic_bus, 0)
|
||||
|
||||
await Multiplayer.noray_connected
|
||||
multiplayer.peer_connected.connect(peer_connected)
|
||||
multiplayer.peer_disconnected.connect(peer_disconnected)
|
||||
multiplayer.server_disconnected.connect(close_network)
|
||||
multiplayer.connection_failed.connect(close_network)
|
||||
multiplayer.connected_to_server.connect(connected)
|
||||
# Set the player name according to the system username. Fallback to the path.
|
||||
if Steamworks.is_initiallized:
|
||||
get_tree().auto_accept_quit = false
|
||||
Steamworks.create_lobby()
|
||||
name_edit.text = Steam.getPersonaName()
|
||||
enableMultiplayer()
|
||||
elif false: #TODO: Set text to saved value
|
||||
name_edit.text = ""
|
||||
else:
|
||||
name_edit.text = "Spacebots Player"
|
||||
|
||||
func _process(_delta: float):
|
||||
|
||||
if Input.is_action_just_pressed("pause") and playersParent.get_child_count() > 0 and %Settingsmenu.visible == false:
|
||||
if not paused:
|
||||
get_tree().paused = true
|
||||
%Pausemenu.show()
|
||||
%Pausemenu.grab_focus() #TODO: fix
|
||||
$Hud.hide()
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CONFINED
|
||||
else:
|
||||
get_tree().paused = false
|
||||
$Hud.show()
|
||||
%Pausemenu.hide()
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
paused = !paused
|
||||
if !mic_capture or Multiplayer.playerDict.is_empty():
|
||||
return
|
||||
while mic_capture.chunk_available():
|
||||
var seq_num : PackedByteArray = PackedByteArray()
|
||||
seq_num.resize(8)
|
||||
seq_num.encode_u64(0,packets_sent+1)
|
||||
var packet = mic_capture.read_opus_packet(seq_num)
|
||||
mic_capture.drop_chunk()
|
||||
if multiplayer.multiplayer_peer.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED:
|
||||
_voice_packet_received.rpc(packet)
|
||||
packets_sent += 1
|
||||
if (packets_sent % 100) == 0:
|
||||
print("Packets sent: ", packets_sent, " from id ", multiplayer.get_unique_id())
|
||||
|
||||
func enableMultiplayer() -> void:
|
||||
$/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer/VBoxMultiplayerDisabled.hide()
|
||||
$/root/Main/Mainmenu/Menu/MarginContainer/VBoxContainer/HBoxContainer/VBoxLobbylist.show()
|
||||
|
||||
func start_game():
|
||||
$Mainmenu.hide()
|
||||
start_btn.disabled = true
|
||||
disconnect_btn.show()
|
||||
$Hud.show()
|
||||
|
||||
func getMapLogicRef() -> MapLogic:
|
||||
return mapsParent.get_child(0)
|
||||
|
||||
@rpc("authority","call_local","reliable")
|
||||
func changeMap(newMap: PackedScene) -> void:
|
||||
if mapsParent.get_child_count():
|
||||
if getMapLogicRef().is_connected(StringName("missionLost"),missionLost):
|
||||
getMapLogicRef().disconnect(StringName("missionLost"),missionLost)
|
||||
mapsParent.get_child(0).queue_free()
|
||||
|
||||
var map = newMap.instantiate()
|
||||
mapsParent.add_child(map)
|
||||
Multiplayer.setCurrentMapLogic(getMapLogicRef())
|
||||
|
||||
await getMapLogicRef().tree_exited
|
||||
getMapLogicRef().missionLost.connect(missionLost)
|
||||
|
||||
func initiatePlayerPosition(position: Vector3) -> void:
|
||||
for player in Multiplayer.alivePlayerDict.values():
|
||||
if player.is_multiplayer_authority():
|
||||
player.position = position
|
||||
|
||||
func missionLost() -> void:
|
||||
changeMap(lobby)
|
||||
|
||||
func stop_game():
|
||||
start_btn.disabled = false
|
||||
disconnect_btn.hide()
|
||||
$Mainmenu.show()
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CONFINED
|
||||
#Steamworks.stop()
|
||||
|
||||
var currentMaps = mapsParent.get_children()
|
||||
for child in currentMaps:
|
||||
child.queue_free()
|
||||
|
||||
var players = playersParent.get_children()
|
||||
for child in players:
|
||||
child.queue_free()
|
||||
|
||||
|
||||
func close_network():
|
||||
peer.close()
|
||||
stop_game()
|
||||
disconnectDialog.popup_centered()
|
||||
disconnectDialog.get_ok_button().grab_focus()
|
||||
multiplayer.multiplayer_peer = null
|
||||
Multiplayer.is_host = false
|
||||
|
||||
|
||||
func connected():
|
||||
if Multiplayer.is_host == false:
|
||||
add_player.rpc_id(1, multiplayer.get_unique_id())
|
||||
#Steamworks.set_player_name.rpc(name_edit.text)
|
||||
|
||||
|
||||
func peer_connected(_id):
|
||||
pass
|
||||
#Steamworks.on_peer_add(id)
|
||||
|
||||
|
||||
func peer_disconnected(id):
|
||||
print("Disconnected %d" % id)
|
||||
#Steamworks.on_peer_del(id)
|
||||
remove_player.rpc_id(1,)
|
||||
|
||||
|
||||
func on_Start_pressed():
|
||||
Multiplayer.host()
|
||||
start_game()
|
||||
changeMap(lobby)
|
||||
add_player(multiplayer.get_unique_id())
|
||||
|
||||
func on_Disconnect_pressed():
|
||||
close_network()
|
||||
|
||||
|
||||
func on_Connect(norayid: String):
|
||||
start_btn.disabled = true
|
||||
start_game()
|
||||
Multiplayer.join(norayid)
|
||||
|
||||
@rpc("any_peer")
|
||||
func add_player(id):
|
||||
var player_instance: CharacterBody3D = player.instantiate()
|
||||
player_instance.name = str(id)
|
||||
playersParent.add_child(player_instance)
|
||||
|
||||
@rpc("any_peer")
|
||||
func remove_player(id):
|
||||
if playersParent.get_node(str(id)):
|
||||
playersParent.get_node(str(id)).queue_free()
|
||||
|
||||
@rpc("any_peer", "unreliable")
|
||||
func _voice_packet_received(packet: PackedByteArray):
|
||||
var sender_id = multiplayer.get_remote_sender_id()
|
||||
var sender_stats = audio_stats.get(sender_id, [0,0,0])
|
||||
if (sender_stats[0]+1 != packet.decode_u32(0)):
|
||||
sender_stats[2]+=1
|
||||
sender_stats[0]=packet.decode_u64(0)
|
||||
sender_stats[1]+=1
|
||||
audio_stats.set(sender_id, sender_stats)
|
||||
if (sender_stats[1] % 100) == 0:
|
||||
print("Packets received: ", sender_stats[1], " from id ", sender_id, " Lossrate: ", sender_stats[2], "/", sender_stats[1], "(" , str(100*(sender_stats[2]/sender_stats[1])), "%)")
|
||||
var VoiceChatPlayerOutputNode: AudioStreamPlayer3D = Multiplayer.playerDict.get(sender_id).get_node("VoiceChat")
|
||||
var OpusStream : AudioStreamOpusChunked = VoiceChatPlayerOutputNode.stream;
|
||||
OpusStream.push_opus_packet(packet, 8, 0)
|
||||
Binary file not shown.
Reference in New Issue
Block a user