mirror of
https://github.com/JohnBreaux/Boat-Battle.git
synced 2025-02-04 12:28:35 +00:00
Game logic (#14)
* Create game classes * Pushing what I've done of the game logic. * Commented my code Deals with ship placement on board and ship rotation on board * Comment game logic code, and edit for style. * Added Clear board button and Confirm Placement button * Fix up some stuff * Pass * I accidentally the buttons + Fix some hitbox mistakes. * Improve hitbox leniency, and don't allow ships to rotate into each other. * Fixed Dialog Box that pops up for Confirm Placement * Update Gameplay.tscn * Partial fire functionality added. Currently hides all ship placement UI and makes visible all fire functionality. The crosshair currently does not snap to a grid. The ships are saved in an area of location objects holding the length, orientation, and coordinates of the ship. * Crosshair now snaps into place * Created Sprites for 2Ship and 3ShipA * Created Sprite for Ship3B * Created Sprite for Ship4 * Created Sprite for Ship5 * Created Sprite for "Hit" * Created Sprites for Ship2 Destroyed and Ship3A Destroyed * Created Sprite for Ship3B Destroyed * Created Sprite for Ship4 Destroyed * Created Sprite for Ship5 Destroyed * Created Sprite for "Miss" * Fixed blurry pixel art Changed texture rendering * Added temporary title screen text * Major restructuring to better support object-oriented design of the main game logic and UI. This was necessary, I swear. * Accidentally offset the Setup menu by a handful of pixels. Whoops. * Setup: remove unused signal * Comment on which parts of Game are only there for testing purposes. * Fixed up the Title Screen text imported font * Fixed Crosshair pixel rendering * Consolidate backgrounds * Added more SFX sounds * Created Sprite for Light Mode * Fix null deref when entering singleplayer after exiting multiplayer * Hien's work * Revert "Hien's work" This reverts commitf099ed6c80. * Stuff * Make git happy by pushing gdengine imports * Put Background in main * Removed option background * Added Confirmation Dialog for Forfeit * Revert "Merge branch 'game-logic' of https://github.com/StatewideInk/Group12 into game-logic" This reverts commit104ffaab0a, reversing changes made to63dec75688. * Fix title screen never going (whoops * Oops I made the background invisible * removed option background again * Added dark/light mode functionality * Added signal for audio SFX * Load the theme on startup * Added Confirmation dialog for Forfeit * Fixed Texture Rendering for Light Mode Background * Sounds no longer scale linearly * Remove unused resourse main.tres * Added victory screen Added a victory screen. Since there is no current way to win, there is a 'win' button added to the top left of the game screen. Once clicked, victory text will appear and the player will be given the option to return to the main menu. * restart button is invisible Co-authored-by: John Breaux <JohnBreaux@my.unt.edu> Co-authored-by: JohnBreaux <89870642+JohnBreaux@users.noreply.github.com> Co-authored-by: hpham474 <HienPham@my.unt.edu> Co-authored-by: Chance Atkinson <chancewatkinson@gmail.com>
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
extends Node
|
||||
|
||||
|
||||
# Ignore "unused signal" warnings in this class
|
||||
# warning-ignore-all:unused_signal
|
||||
|
||||
# Ask for a scene change
|
||||
signal button_clicked
|
||||
@@ -1,18 +0,0 @@
|
||||
extends Area2D
|
||||
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
#func _process(delta):
|
||||
# pass
|
||||
|
||||
func _on_Border_body_entered(body):
|
||||
print(body)
|
||||
@@ -1,13 +0,0 @@
|
||||
extends Control
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
if find_next_valid_focus(): find_next_valid_focus().grab_focus()
|
||||
|
||||
|
||||
func _on_Forfeit_pressed():
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
queue_free();
|
||||
MessageBus.emit_signal("change_scene", "Title")
|
||||
|
||||
54
godot_ship/script/game/Gameplay/Board.gd
Normal file
54
godot_ship/script/game/Gameplay/Board.gd
Normal file
@@ -0,0 +1,54 @@
|
||||
extends Node
|
||||
|
||||
# Path to Ship class, for instantiating new Ships in code
|
||||
onready var Ship = load("res://script/game/Gameplay/Ship.gd")
|
||||
|
||||
var bottom_board # Player board
|
||||
var top_board # Opponent board
|
||||
var ships # list of Ships
|
||||
var ship_count # number of 'active' (un-sunk) ships
|
||||
|
||||
# a board is square. This is its side lengths
|
||||
var board_len = 10
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
ships = []
|
||||
ship_count = 0
|
||||
|
||||
# TODO: What state?
|
||||
func getState():
|
||||
pass
|
||||
|
||||
# Place a ship on the board at board-space coordinates
|
||||
func placeShip(in_position, in_size, in_orientation):
|
||||
ships.append(Ship.new(in_position, in_size, in_orientation))
|
||||
pass
|
||||
|
||||
func getBottomBoard():
|
||||
pass
|
||||
|
||||
func getShipCount():
|
||||
return ship_count
|
||||
|
||||
func _init():
|
||||
# Initialize the bottom_board to a 10x10 array
|
||||
for _row in range(board_len):
|
||||
bottom_board.append([])
|
||||
for column in bottom_board:
|
||||
column.resize(10)
|
||||
# Initialize the top_board to a 10x10 array
|
||||
for _row in range(board_len):
|
||||
top_board.append([])
|
||||
for column in top_board:
|
||||
column.resize(board_len)
|
||||
|
||||
# worldspace_to_boardspace: convert a Vector2 in world-space to board-space
|
||||
func worldspace_to_boardspace(coordinate:Vector2):
|
||||
# subtract 36 to get the position relative to (0,0) on the board, and integer divide by 32
|
||||
return Vector2(int(coordinate.x - 36) >> 5, int(coordinate.y-36) >> 5)
|
||||
|
||||
# Coordinates of ship's center. Ship extends [-(size-1 >> 1), (size/2 >> 1)]
|
||||
func shiptoboard(ship:Ship):
|
||||
for i in range (ship.)
|
||||
pass
|
||||
58
godot_ship/script/game/Gameplay/Crosshair.gd
Normal file
58
godot_ship/script/game/Gameplay/Crosshair.gd
Normal file
@@ -0,0 +1,58 @@
|
||||
extends Sprite
|
||||
|
||||
|
||||
var snapped = false #when snapped if true crosshair stops following mouse
|
||||
const world_offset = Vector2(36,36)
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
# Move the cursor to 0,0
|
||||
position = board_to_world_space(Vector2(-2,-2))
|
||||
pass # Replace with function body.
|
||||
|
||||
func _physics_process(_delta):
|
||||
var mousePos = get_global_mouse_position()
|
||||
# If the cursor is not snapped, and the mouse is over the board
|
||||
if snapped == false and validate_position(mousePos):
|
||||
# Snap the crosshair to the grid, but following the mouse
|
||||
position = (mousePos - world_offset).snapped(Vector2(32,32)) + world_offset
|
||||
|
||||
func _input(event):
|
||||
# Check if left click is being clicked and the sprite is visible (i.e only checks for inputs after ship positions are confirmed)
|
||||
if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and visible and not event.is_pressed():
|
||||
# Make a noise
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
# Locks the position of the crosshair with left click release
|
||||
if validate_position(position) == true:
|
||||
# rounds the board position to the nearest integer
|
||||
snapped = true
|
||||
position.x = int(round(world_to_board_space(position).x))
|
||||
position.y = int(round(world_to_board_space(position).y))
|
||||
position = board_to_world_space(position)
|
||||
# Check if left click is being clicked and the sprite is visible (i.e only checks for inputs after ship positions are confirmed)
|
||||
elif event is InputEventMouseButton and event.button_index == BUTTON_LEFT and visible == true:
|
||||
# Unlocks the position of the crosshair with left click
|
||||
snapped = false
|
||||
|
||||
func validate_position(vector):
|
||||
# rounds the board position to the nearest integer
|
||||
var board = world_to_board_space(vector)
|
||||
# Checks if the board position is within bounds of the board
|
||||
if board.x < 9.5 and board.x >= -0.5 and board.y < 9.5 and board.y >= -0.5:
|
||||
# changes the position of the crosshair
|
||||
return true
|
||||
else:
|
||||
# unlocks the crosshair if not within bounds
|
||||
return false
|
||||
|
||||
# Convert the world-space coordinates to positions on the board
|
||||
func world_to_board_space(vector):
|
||||
# Do math
|
||||
var res = (vector - world_offset) / 32 # Basically Fahrenheit/Celcius conversion, but in 2D
|
||||
return res
|
||||
|
||||
# Inverse of the above function.
|
||||
func board_to_world_space(vector):
|
||||
# Do math
|
||||
var res = (vector * 32) + world_offset #Invert the above function
|
||||
return res #Truncate decimals
|
||||
30
godot_ship/script/game/Gameplay/Fire.gd
Normal file
30
godot_ship/script/game/Gameplay/Fire.gd
Normal file
@@ -0,0 +1,30 @@
|
||||
extends Control
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
# Signal to pass the fire location back to yet-unknown nodes
|
||||
signal fire_at
|
||||
|
||||
|
||||
func _on_Fire_pressed():
|
||||
var crosshair = get_node("Crosshair")
|
||||
# hides crosshair
|
||||
crosshair.visible = false
|
||||
if crosshair.validate_position(crosshair.position) == true:
|
||||
var crosshair_pos = crosshair.world_to_board_space(crosshair.position)
|
||||
# fires at position
|
||||
print("Fire at position: ", crosshair_pos)
|
||||
emit_signal("fire_at", crosshair_pos)
|
||||
# Close the Firing menu
|
||||
queue_free()
|
||||
else:
|
||||
#if invalid position popup appears
|
||||
var dialog = get_node("FireDialog")
|
||||
dialog.popup_centered()
|
||||
pass # Replace with function body.
|
||||
|
||||
func _on_FireDialog_confirmed():
|
||||
get_node("Crosshair").visible = true
|
||||
pass # Replace with function body.
|
||||
75
godot_ship/script/game/Gameplay/Game.gd
Normal file
75
godot_ship/script/game/Gameplay/Game.gd
Normal file
@@ -0,0 +1,75 @@
|
||||
extends Node
|
||||
|
||||
class ShipData:
|
||||
var Coor: Vector2
|
||||
var Length: int
|
||||
var Orientation: bool #vertical is true, (Trueship = vertical) (Falseship = horizontal)
|
||||
|
||||
# Preloaded assets, to be used later
|
||||
# TODO: Move Setup into the Player. It's just here, for now, so that it can be tested and the game doesn't appear broken
|
||||
onready var Setup = preload("res://scenes/Game/Setup.tscn")
|
||||
# TODO: Move Fire into the Player. See above.
|
||||
onready var Fire = preload("res://scenes/Game/Fire.tscn")
|
||||
|
||||
# Path to Player class, for instantiating new Players in code
|
||||
onready var Player = preload("res://scenes/Game/Player.tscn")
|
||||
|
||||
onready var Victory = preload("res://scenes/Game/Victory.tscn")
|
||||
|
||||
|
||||
# Array of instances of the Player class; stores the Players
|
||||
var players # = player1, player2, ...
|
||||
# turn counter
|
||||
var turn = 0
|
||||
# Variable transporting hit state between players
|
||||
var hit = false
|
||||
# Variable tracking whether a game is multiplayer (so that the correct Player type can be spawned)
|
||||
# TODO: Multiplayer
|
||||
var is_multiplayer = false
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
# TODO: Move Setup into the Player.
|
||||
var setup = Setup.instance()
|
||||
setup.connect("game_ready", self, "game_setup")
|
||||
add_child(setup)
|
||||
|
||||
get_node("ConfirmationDialog").get_ok().text = "Yes"
|
||||
get_node("ConfirmationDialog").get_cancel().text = "No"
|
||||
|
||||
# TODO: Move Setup into the Player.
|
||||
func game_setup(_ships):
|
||||
print_debug("Congrats! Setup complete.")
|
||||
# TODO: Move Fire into the Player.
|
||||
add_child(Fire.instance())
|
||||
|
||||
# Member functions:
|
||||
# game_start: starts the game
|
||||
func game_start():
|
||||
pass
|
||||
|
||||
# victory_screen: display the victory screen
|
||||
func victory_screen():
|
||||
# TODO: Create the victory screen, fill it with knowledge
|
||||
pass
|
||||
|
||||
# display_turn(): display which turn it is on the screen
|
||||
func display_turn():
|
||||
# TODO: Update the turn display, if there is one?
|
||||
pass
|
||||
|
||||
func _on_Forfeit_pressed():
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
get_node("ConfirmationDialog").popup()
|
||||
|
||||
func end():
|
||||
queue_free()
|
||||
|
||||
func _on_Button_button_down():
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
var victory = Victory.instance()
|
||||
add_child(victory)
|
||||
victory.connect("exit_main", self, "end")
|
||||
|
||||
func _on_ConfirmationDialog_confirmed():
|
||||
end()
|
||||
55
godot_ship/script/game/Gameplay/Player.gd
Normal file
55
godot_ship/script/game/Gameplay/Player.gd
Normal file
@@ -0,0 +1,55 @@
|
||||
extends Node
|
||||
|
||||
# Path to Board class, for instantiating new Boards in code
|
||||
var Board = "res://script/game/Gameplay/Board.gd"
|
||||
|
||||
# Player ID of this player
|
||||
var pid
|
||||
# board (an instance of the Board class)
|
||||
onready var board = Board.new()
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
# Member functions:
|
||||
# hit: Called when opponent fires on us.
|
||||
# Update internal state, and return bool hit/miss
|
||||
func hit():
|
||||
pass
|
||||
|
||||
# place_ship: called when ships are placed.
|
||||
# forwards Ship locations to the Board, so that it may construct a ship
|
||||
# ship: a list of ship properties {position, orientation, size}
|
||||
func place_ship(_ship):
|
||||
pass
|
||||
|
||||
# setUp: set up the board given the placed ship locations
|
||||
# translates the ship positions in the Setup UI to board-space, then places each ship
|
||||
# ships: a list of lists of ship properties {{position, orientation, size}, ...}
|
||||
func set_up(_ships):
|
||||
pass
|
||||
|
||||
# turnStart: start player's turn
|
||||
# Initiates the player's turn, and blocks until the player selects a location to fire upon
|
||||
# returns: fire = [player id, target coordinates]
|
||||
func turnStart():
|
||||
var player_id = 0
|
||||
var target = Vector2(0,0)
|
||||
return [player_id, target]
|
||||
pass
|
||||
|
||||
# getBoard: returns the player's board
|
||||
# returns: board
|
||||
func getBoard():
|
||||
return board
|
||||
|
||||
# forfeit: ends game for player
|
||||
# Sinks all ships
|
||||
func forfeit():
|
||||
pass
|
||||
|
||||
# getShipCount: get the number of ships the player has left alive
|
||||
func getShipCount():
|
||||
pass
|
||||
|
||||
55
godot_ship/script/game/Gameplay/Ship.gd
Normal file
55
godot_ship/script/game/Gameplay/Ship.gd
Normal file
@@ -0,0 +1,55 @@
|
||||
extends Node
|
||||
|
||||
# This is the rendered element of a "ship", generated when the game transitions from the placing state to the gameplay state
|
||||
|
||||
# Enum denoting the orientation (X is 1, Y is 0)
|
||||
enum Orientation {X = 1, Y = 0}
|
||||
|
||||
# Size of ship in board units
|
||||
var size
|
||||
# Coordinates of ship's center. Ship extends [-(size-1 >> 1), (size/2 >> 1)]
|
||||
var position
|
||||
# Variable storing whether the ship is sunk, for rendering purposes
|
||||
var sunk = false
|
||||
# Orientation of the ship (see enum Orientation)
|
||||
var orientation = Orientation.Y
|
||||
|
||||
# Ship sprite metadata
|
||||
# sprite: the texture atlas containing all ship parts
|
||||
var atlas # = TODO: figure out how to use one sprite for multiple textures
|
||||
# texture: the offset into the texture atlas of the first part of the ship.
|
||||
var texture = 0
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
# member functions:
|
||||
# getSize: get the size of the ship, in board-units (2 for 2-ship, 3 for 3-ship, ...)
|
||||
func getSize():
|
||||
return size
|
||||
|
||||
# getPosition: get the position of the ship's center, in board units
|
||||
func getPosition():
|
||||
return position
|
||||
|
||||
# getOrientation: get the orientation of the ship (see enum Orientation)
|
||||
func getOrientation():
|
||||
return orientation
|
||||
|
||||
# getSunk: get whether the ship is sunk
|
||||
func getSunk():
|
||||
return sunk
|
||||
|
||||
# setSunk: sink the ship
|
||||
func setSunk():
|
||||
sunk = true
|
||||
|
||||
# _init: called on object initialization. Accepts args if called via <Ship>.new(...)
|
||||
# in_position: position of the ship, in board-coordinates; (0,0) by default
|
||||
# in_size: size of the ship, in board-units; 2 by default
|
||||
# in_orientation: orientation of the ship (see enum Orientation); vertical by default
|
||||
func _init(in_position = Vector2(0,0), in_size = 2, in_orientation = Orientation.Y):
|
||||
position = in_position
|
||||
size = in_size
|
||||
orientation = in_orientation
|
||||
@@ -1,89 +0,0 @@
|
||||
extends Control
|
||||
|
||||
# Scenes
|
||||
onready var title_screen = preload("res://scenes/Title Screen.tscn")
|
||||
onready var gameplay = preload("res://scenes/Gameplay.tscn" )
|
||||
onready var options = preload("res://scenes/Options.tscn" )
|
||||
onready var debug_menu = preload("res://scenes/Debug Menu.tscn" )
|
||||
|
||||
#flags
|
||||
var power_saving = true
|
||||
var debug_enabled = true
|
||||
var start_fullscreen = false
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
# Connect to signals
|
||||
var _errno = 0;
|
||||
_errno += MessageBus.connect("start_tcsn" , self, "_on_scene_start_by_name")
|
||||
_errno += MessageBus.connect("change_scene" , self, "_on_scene_start" )
|
||||
_errno += MessageBus.connect("kill_scene" , self, "_on_scene_kill" )
|
||||
_errno += MessageBus.connect("list_scenes" , self, "_on_scene_list" )
|
||||
_errno += MessageBus.connect("quit" , self, "_on_quit_request" )
|
||||
_errno += MessageBus.connect("return_to_title", self, "_on_title_request" )
|
||||
# go fullscreen
|
||||
OS.low_processor_usage_mode = power_saving
|
||||
OS.low_processor_usage_mode_sleep_usec = 6800
|
||||
OS.window_fullscreen = start_fullscreen
|
||||
if debug_enabled:
|
||||
add_child(debug_menu.instance())
|
||||
|
||||
# Process global keybinds
|
||||
func _input(event):
|
||||
if event.is_action_pressed("ui_fullscreen"):
|
||||
# toggle_fullscreen
|
||||
OS.window_fullscreen = !OS.window_fullscreen
|
||||
|
||||
|
||||
# Ensure the scene doesn't become empty
|
||||
func _process(_delta):
|
||||
# Make sure there's something running
|
||||
# Debug counts as one child
|
||||
if get_child_count() < 1 + int(debug_enabled):
|
||||
MessageBus.emit_signal("change_scene", "Title")
|
||||
pass
|
||||
|
||||
# Creates a new instance of each menu scene
|
||||
func _on_scene_start(scene):
|
||||
#print ("_on_scene_start(",scene,")")
|
||||
match scene:
|
||||
"Singleplayer":
|
||||
add_child (gameplay.instance())
|
||||
return true
|
||||
"Multiplayer":
|
||||
add_child (gameplay.instance())
|
||||
# add_child (multiplayercontroller.instance())
|
||||
return true
|
||||
"Options":
|
||||
add_child (options.instance())
|
||||
return true
|
||||
"Title":
|
||||
add_child (title_screen.instance())
|
||||
return true
|
||||
|
||||
func _on_scene_start_by_name(scene):
|
||||
var pack = load("res://scenes/" + scene + ".tscn");
|
||||
add_child(pack.instance());
|
||||
|
||||
# Kills all child nodes with name matching `scene`
|
||||
func _on_scene_kill(scene):
|
||||
var node = find_node(scene, false, false)
|
||||
if node :
|
||||
node.queue_free()
|
||||
MessageBus.emit_signal("print_console", String(node.name) + " killed.\n".c_unescape())
|
||||
|
||||
func _on_scene_list():
|
||||
var children = get_children()
|
||||
var names = []
|
||||
for i in range (children.size()):
|
||||
names.append(children[i].name)
|
||||
MessageBus.emit_signal("print_console", String(names) + "\n".c_unescape())
|
||||
|
||||
|
||||
# Quits
|
||||
func _on_quit_request():
|
||||
get_tree().quit()
|
||||
|
||||
# Kills the current tree and replaces it with a new one
|
||||
func _on_title_request():
|
||||
return get_tree().change_scene("res://scenes/Main.tscn")
|
||||
@@ -1,20 +0,0 @@
|
||||
extends Node
|
||||
|
||||
# Ignore "unused signal" warnings in this class
|
||||
# warning-ignore-all:unused_signal
|
||||
|
||||
# Ask for a scene change
|
||||
signal change_scene(scene_name)
|
||||
|
||||
signal start_tcsn(scene_tcsn_name)
|
||||
# Ask to kill scene
|
||||
signal kill_scene(scene_name)
|
||||
# Ask to list active scenes
|
||||
signal list_scenes()
|
||||
# Ask to quit the game
|
||||
signal quit
|
||||
# Ask to return to title screen
|
||||
signal return_to_title
|
||||
|
||||
# Ask to print a string to debug console
|
||||
signal print_console(string)
|
||||
55
godot_ship/script/game/Setup.gd
Normal file
55
godot_ship/script/game/Setup.gd
Normal file
@@ -0,0 +1,55 @@
|
||||
extends Control
|
||||
|
||||
signal game_ready
|
||||
|
||||
onready var Ships = ["2Ship", "3ShipA", "3ShipB", "4Ship", "5Ship"]
|
||||
|
||||
onready var Victory = preload("res://scenes/Game/Player.tscn")
|
||||
|
||||
class ShipData:
|
||||
var Position: Vector2
|
||||
var Length: int
|
||||
var Orientation: bool # (True = vertical) (False = horizontal)
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
# Moves the focus to this menu
|
||||
if find_next_valid_focus(): find_next_valid_focus().grab_focus()
|
||||
|
||||
|
||||
func _on_Confirm_Placement_pressed():
|
||||
# Make the button noise
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
var valid = true
|
||||
for ship in Ships:
|
||||
# validate_placement returns the x-axis distance from the board
|
||||
# if this is more than zero, the ship is invalid
|
||||
if get_node(ship).validate_placement():
|
||||
valid = false
|
||||
print ("Placement: ", valid)
|
||||
if valid == false:
|
||||
get_node("PlaceShipDialog").popup()
|
||||
else:
|
||||
#Saves the location of ships and length of ship into an array
|
||||
var shipLocation = []
|
||||
for ship in Ships:
|
||||
var location = ShipData.new()
|
||||
location.Position = get_node(ship).position
|
||||
location.Length = get_node(ship).get("ship_length")
|
||||
location.Orientation = get_node(ship).get("vertical")
|
||||
shipLocation.append(location)
|
||||
|
||||
#print out the array for testing
|
||||
for x in shipLocation:
|
||||
print("Ship Length: ", x.Length, ", Ship Orientation: ", x.Orientation, ", Ship Position: ", x.Position)
|
||||
|
||||
# Return the shipLocation array to those listening on game_ready
|
||||
emit_signal("game_ready", shipLocation)
|
||||
queue_free()
|
||||
return valid # Replace with function body.
|
||||
|
||||
func _on_Clear_pressed():
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
for ship in Ships:
|
||||
get_node(ship).clear()
|
||||
pass # Replace with function body.
|
||||
@@ -2,21 +2,24 @@ extends RigidBody2D
|
||||
|
||||
|
||||
var held = false
|
||||
var originalPos
|
||||
var snapOriginalPos = false
|
||||
var mousePos
|
||||
var vertical = true
|
||||
var startingPos
|
||||
var originalPos # Position before moving the ship
|
||||
var snapOriginalPos = false # Gets the original position
|
||||
var mousePos # Stores the last known mouse position so the physics engine can use it
|
||||
var vertical = true # Gets ship which is either vertical or horizonal
|
||||
var startingPos # Starting position of ships before being placed
|
||||
|
||||
# Ships are all named starting with their length,
|
||||
# So we cast from string to int, on the ship name, and get the length
|
||||
onready var ship_length = int(name)
|
||||
|
||||
# This is set when we're colliding with something
|
||||
var collision = false
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
mode = MODE_KINEMATIC
|
||||
contacts_reported = 64
|
||||
set_use_custom_integrator(true)
|
||||
# Snap the ships to the grid, so the engine won't get mad when they're moved away from the starting position every frame
|
||||
position = (position - offset).snapped(Vector2(32, 32)) + offset
|
||||
startingPos = position
|
||||
@@ -42,10 +45,8 @@ func _input(event):
|
||||
var bs_position = world_to_board_space(position)
|
||||
# Check whether the piece is within half a board-space of the grid (-0.5, 9.5)
|
||||
if not (bs_position.x > -0.5 and bs_position.x < 9.5 and bs_position.y > -0.5 and bs_position.y < 9.5):
|
||||
# if not (position.x > 17.4 and position.x < 335.5) and (position.y > 20.2 and position.y < 335.5):
|
||||
if originalPos != null:
|
||||
collision = true
|
||||
rotation = 0
|
||||
vertical = true
|
||||
|
||||
if event is InputEventMouseMotion and held:
|
||||
@@ -56,21 +57,16 @@ func _input(event):
|
||||
mousePos = event.position;
|
||||
|
||||
if event.is_action_pressed("ui_rotate"):
|
||||
if held:
|
||||
return
|
||||
if checkOriginalPos():
|
||||
return
|
||||
else:
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
if originalPos == null:
|
||||
if position == originalPos:
|
||||
return
|
||||
elif(event.position - position).length() < click_radius:
|
||||
if not held and not checkOriginalPos():
|
||||
if(event.position - position).length() < click_radius:
|
||||
#Play a sound
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
# Rotation has been moved to _physics_process,
|
||||
# as per recommendation of godot_engine.org
|
||||
#rotation = (-PI/2)
|
||||
vertical = not vertical
|
||||
|
||||
# It takes 3 physics ticks for the rotation to update the hitboxes
|
||||
# Determined imperically through testing, may work differently on different machines(?)
|
||||
released = 3
|
||||
|
||||
# Offset from the corner of the screen to the corner of the board
|
||||
const offset = Vector2(36, 36)
|
||||
@@ -88,21 +84,17 @@ func _physics_process(_delta):
|
||||
# calculate whether the piece has been rotated or moved
|
||||
var rotated = prev_vertical != vertical
|
||||
var moved = prev_position != position
|
||||
|
||||
|
||||
# If the piece is held, move it to the mouse:
|
||||
if held and mousePos and mousePos != position:
|
||||
position = mousePos
|
||||
mousePos = null
|
||||
|
||||
|
||||
# Snap it to the grid if not held (and previously moved)
|
||||
if not held and moved:
|
||||
position = (position - offset).snapped(Vector2(32, 32)) + offset
|
||||
prev_position = position
|
||||
|
||||
# Check collisions after released, reset if colliding
|
||||
if collision and released:
|
||||
position = startingPos
|
||||
|
||||
|
||||
# If it's been moved or rotated, snap it to the board
|
||||
if released or rotated:
|
||||
# check whether the ends of the piece are within the board
|
||||
@@ -114,12 +106,18 @@ func _physics_process(_delta):
|
||||
else:
|
||||
position += 32 * Vector2(linear_move, 0)
|
||||
pass
|
||||
|
||||
|
||||
# Check collisions after released, reset if colliding
|
||||
if collision and released:
|
||||
position = startingPos
|
||||
rotation = 0
|
||||
vertical = true
|
||||
|
||||
# Rotate if the piece needs to be rotated
|
||||
if rotated:
|
||||
prev_vertical = vertical
|
||||
rotation = -PI/2 * int(not vertical) # int(true) == 1, int(false) == 0
|
||||
|
||||
|
||||
# Count down the number of physics timesteps left until the piece can stop processing
|
||||
if released > 0:
|
||||
released = released - 1
|
||||
@@ -152,29 +150,36 @@ func ship_unstacked(_body):
|
||||
# Returns how many squares to move the ship along its orientation axis (positive or negative)
|
||||
func check_extents(center, orientation, length):
|
||||
center = world_to_board_space(center) # Convert to board-space (0-10)
|
||||
print("Center: ", center)
|
||||
# Calculate the position of the front of the ship
|
||||
# Orientation is true when the ship is vertical
|
||||
var bow = vectorget(center, orientation) - floor((length - 1) / 2)
|
||||
print("Bow: ", bow)
|
||||
# if out of bounds, return how much to move the ship by
|
||||
if bow < 0:
|
||||
print("return: ", -bow)
|
||||
return -bow
|
||||
# Calculate the position of the rear of the ship
|
||||
var stern = vectorget(center, orientation) + floor(length / 2)
|
||||
print("Stern: ", stern)
|
||||
# If out of bounds, return how much to move the ship by
|
||||
if stern >= 10:
|
||||
print("return: ", -(stern - 9))
|
||||
return -(stern - 9)
|
||||
print("return: ", 0)
|
||||
return 0
|
||||
|
||||
func validate_placement():
|
||||
# Checks whether the ship's center is on the board.
|
||||
# As long as the ship was moved according to the rules defined in the
|
||||
# _physics_process function, this should be necessary and sufficient
|
||||
# to say the ship is on the board
|
||||
return check_extents(position, false, 1)
|
||||
|
||||
func clear():
|
||||
# ships return home on collision
|
||||
# simulate a collision
|
||||
collision = true
|
||||
released = 1
|
||||
|
||||
# Convert the world-space coordinates to positions on the board
|
||||
func world_to_board_space(vector):
|
||||
# Do math
|
||||
var res = (vector - offset) / 32 # Subtract the distance between the screen corner and square (0,0)
|
||||
var res = (vector - offset) / 32 # Basically Fahrenheit/Celcius conversion, but in 2D
|
||||
return res
|
||||
|
||||
# Inverse of the above function.
|
||||
30
godot_ship/script/game/Victory.gd
Normal file
30
godot_ship/script/game/Victory.gd
Normal file
@@ -0,0 +1,30 @@
|
||||
extends Control
|
||||
|
||||
signal exit_main
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
#func _process(delta):
|
||||
# pass
|
||||
|
||||
|
||||
# returns player(s) back to main menu
|
||||
func _on_Button_pressed():
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
#MessageBus.emit_signal("change_scene", "Title")
|
||||
emit_signal("exit_main")
|
||||
|
||||
|
||||
func _on_restart_button_down():
|
||||
AudioBus.emit_signal("button_clicked")
|
||||
#MessageBus.emit_signal("change_scene", "Multiplayer")
|
||||
pass # Replace with function body.
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
extends Node
|
||||
|
||||
|
||||
# Declare member variables here. Examples:
|
||||
# var a = 2
|
||||
# var b = "text"
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
#func _process(delta):
|
||||
# pass
|
||||
Reference in New Issue
Block a user