All cards by default now have 2.5mm rounded corners.

In the future, I will allow the size of the corners to be changed
via the config file.

This commit fixes #182.
This commit is contained in:
drwhut 2024-10-01 12:38:30 +01:00
parent 488661f9fd
commit 0706f21e58
7 changed files with 109 additions and 13 deletions

View File

@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Both 'Picnic Bench' and 'Table' are now textured.
- Objects now have a black outline when they are unselected, and a grey outline
when they are locked in place.
- All cards in the default asset pack now have rounded corners.
#### Commands

View File

@ -318,7 +318,9 @@ func setup_scene_entry_custom(entry: AssetEntryScene, scene_file_name: String) -
# loaded and freed in the main thread. Looking at the source code, it
# looks like forcing no cache loading may work, as it should just load
# the resource from scratch every time as unique references.
var packed_scene := ResourceLoader.load(scene_file_path, "PackedScene") as PackedScene
var packed_scene := ResourceLoader.load(scene_file_path, "PackedScene",
true) as PackedScene
if packed_scene != null:
var scene := packed_scene.instance()

View File

@ -0,0 +1,66 @@
# tabletop-club
# Copyright (c) 2020-2024 Benjamin 'drwhut' Beddows.
# Copyright (c) 2021-2024 Tabletop Club contributors (see game/CREDITS.tres).
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
extends Node
## A cache for generated card meshes with various corner sizes.
var _mesh_cache := {}
## For the given card scale and corner size, get the corresponding [Mesh] using
## the [CardMeshGenerator].
##
## The resulting [Mesh] is cached, so that it is not re-generated when using the
## same parameters.
func get_mesh(card_scale: Vector2, corner_size: Vector2) -> Mesh:
var key := [ card_scale, corner_size ]
if _mesh_cache.has(key):
return _mesh_cache[key]
print("CardMeshCache: Generating mesh for scale = %s, corner_size = %s ..." %
[str(card_scale), str(corner_size)])
var generator := CardMeshGenerator.new()
# Generate a mesh with a unit size, and let the ObjectBuilder scale it like
# all other pieces afterwards.
generator.extents = Vector3(0.5, 0.01, 0.5)
if is_zero_approx(card_scale.x):
push_error("X-scale of card cannot be 0")
card_scale.x = 1.0
if is_zero_approx(card_scale.y):
push_error("Y-scale of card cannot be 0")
card_scale.y = 1.0
generator.corner_start = Vector2(0.5, 0.5) - (corner_size / card_scale)
# Aim for roughly one vertex per in-game 0.25mm.
var max_size := max(corner_size.x, corner_size.y)
generator.corner_points = 4 * (1 + int(max_size))
# Generate the mesh, and cache it.
var mesh := generator.generate()
_mesh_cache[key] = mesh
return mesh

View File

@ -43,6 +43,20 @@ func build_piece(piece_entry: AssetEntryScene) -> Piece:
if instance is Piece:
piece_node = instance
# Cards need to be given their own custom meshes, since they can have
# differing corners.
if piece_entry.scene_path == "res://assets/scenes/card.tscn":
var collision_shape: CollisionShape = piece_node.get_child(0)
var mesh_instance: MeshInstance = collision_shape.get_child(0)
mesh_instance.mesh = CardMeshCache.get_mesh(
Vector2(piece_entry.scale.x, piece_entry.scale.z),
Vector2(0.25, 0.25)) # TODO: Editable corner size.
# Can't set multiple surface materials in the editor, so need to
# add them in code.
mesh_instance.set_surface_material(0, SpatialMaterial.new())
mesh_instance.set_surface_material(1, SpatialMaterial.new())
# All materials need to be instanced individually, so that each piece
# can be modified separately. As far as I can tell, with the way the
# in-built scenes are constructed, there is no way to set the materials
@ -107,10 +121,31 @@ func build_piece(piece_entry: AssetEntryScene) -> Piece:
adjust_centre_of_mass(piece_node, piece_entry, false)
# TODO: Assign textures.
piece_node.set_user_albedo(piece_entry.albedo_color)
# If the entry tells us to override the piece's textures, do so here.
if not piece_entry.texture_overrides.empty():
var material_list := piece_node.get_materials()
if piece_entry.texture_overrides.size() != material_list.size():
push_warning("Texture override count (%d) does not match material count (%d)" % [
piece_entry.texture_overrides.size(), material_list.size()])
var index := 0
while (
index < piece_entry.texture_overrides.size() and
index < material_list.size()
):
var material: SpatialMaterial = material_list[index]
var texture_path: String = piece_entry.texture_overrides[index]
var texture := ResourceLoader.load(texture_path, "Texture") as Texture
if texture != null:
material.albedo_texture = texture
else:
push_error("Failed to load texture override '%s'" % texture_path)
index += 1
# TODO: Setup outline materials.
# TODO: Set up collision sound effects.

Binary file not shown.

View File

@ -1,15 +1,10 @@
[gd_scene load_steps=6 format=2]
[gd_scene load_steps=3 format=2]
[ext_resource path="res://assets/objects/stackable.gd" type="Script" id=1]
[ext_resource path="res://assets/scenes/card.mesh" type="ArrayMesh" id=2]
[sub_resource type="BoxShape" id=1]
extents = Vector3( 0.5, 0.01, 0.5 )
[sub_resource type="SpatialMaterial" id=2]
[sub_resource type="SpatialMaterial" id=3]
[node name="Card" type="RigidBody"]
contacts_reported = 1
contact_monitor = true
@ -24,7 +19,3 @@ NOTE: Due to the fact that cards can have varying meshes, the scenes MeshInstanc
shape = SubResource( 1 )
[node name="MeshInstance" type="MeshInstance" parent="CollisionShape"]
transform = Transform( 1, 0, 0, 0, 0.01, 0, 0, 0, 1, 0, 0, 0 )
mesh = ExtResource( 2 )
material/0 = SubResource( 2 )
material/1 = SubResource( 3 )

View File

@ -698,6 +698,7 @@ DataBroadcaster="*res://network/transfer/data_broadcaster.gd"
AssetTree="*res://assets/nodes/asset_tree.gd"
ShapeUtil="*res://util/shape_util.gd"
ControllerDetector="*res://util/controller_detector.gd"
CardMeshCache="*res://assets/card_mesh_cache.gd"
[debug]