|
|
@ -9,7 +9,6 @@ static func lookup(id: int) -> Shape: |
|
|
|
static var EMPTY : Shape |
|
|
|
static var EMPTY : Shape |
|
|
|
static var FULL : Shape |
|
|
|
static var FULL : Shape |
|
|
|
|
|
|
|
|
|
|
|
## Default shape to return when chunk or layer is not found. |
|
|
|
|
|
|
|
static var DEFAULT : Shape |
|
|
|
static var DEFAULT : Shape |
|
|
|
|
|
|
|
|
|
|
|
var id : int |
|
|
|
var id : int |
|
|
@ -35,14 +34,12 @@ func _init(base: Base, mirror: bool, angle: int, shape: Shape2D, points: PackedV |
|
|
|
uvs.append((Vector2.ONE / 2) + point) |
|
|
|
uvs.append((Vector2.ONE / 2) + point) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Represents a base shape, before it has been rotated and mirrored |
|
|
|
|
|
|
|
## (if applicable) to create a number of variants based on that shape. |
|
|
|
|
|
|
|
class Base: |
|
|
|
class Base: |
|
|
|
static var EMPTY := Base.new("empty") |
|
|
|
static var EMPTY := Base.new("empty") |
|
|
|
static var FULL := Base.new("full" , _rect()) |
|
|
|
static var FULL := Base.new("full" , _rect()) |
|
|
|
static var HALF := Base.new("half" , [ 0,1, 2,1, 2,2, 0,2 ], true) |
|
|
|
static var HALF := Base.new("half" , [ 0,1, 2,1, 2,2, 0,2 ], true) |
|
|
|
static var SLOPE := Base.new("slope" , [ 0,1, 1,0, 1,1 ], true) |
|
|
|
static var SLOPE := Base.new("slope" , [ 0,1, 1,0, 1,1 ], true) |
|
|
|
static var HALF_SLOPE := Base.new("half_slope" , [ 0,2, 2,1, 2,2 ], true, true) |
|
|
|
static var HALF_SLOPE := Base.new("half_slope" , [ 0,2, 1,0, 2,2 ], true, true) |
|
|
|
static var HALF_SLOPE_BIG := Base.new("half_slope_big", [ 0,1, 2,0, 2,2, 0,2 ], true, true) |
|
|
|
static var HALF_SLOPE_BIG := Base.new("half_slope_big", [ 0,1, 2,0, 2,2, 0,2 ], true, true) |
|
|
|
|
|
|
|
|
|
|
|
static func _static_init() -> void: |
|
|
|
static func _static_init() -> void: |
|
|
@ -63,25 +60,28 @@ class Base: |
|
|
|
shape = _rotate(shape) # rotate by 90 degrees (swap x and y components) |
|
|
|
shape = _rotate(shape) # rotate by 90 degrees (swap x and y components) |
|
|
|
variants.append(Shape.new(self, false, 0, shape, _points(shape))) |
|
|
|
variants.append(Shape.new(self, false, 0, shape, _points(shape))) |
|
|
|
elif shape is Array: |
|
|
|
elif shape is Array: |
|
|
|
# Convert points (pairs of `int`s) in `Array` to convex shape. |
|
|
|
# Convert points (pairs of ints) in array to convex shape. |
|
|
|
var factor := float(shape.max()) |
|
|
|
var factor := float(shape.max()) |
|
|
|
var points_orig := PackedVector2Array() # untransformed points |
|
|
|
var points := PackedVector2Array() |
|
|
|
for i in range(0, shape.size(), 2): |
|
|
|
for i in range(0, shape.size(), 2): |
|
|
|
var point := Vector2(shape[i] / factor, shape[i + 1] / factor) |
|
|
|
var point := Vector2(shape[i] / factor, shape[i + 1] / factor) |
|
|
|
points_orig.append(point - (Vector2.ONE / 2)) # ensure shape is centered |
|
|
|
points.append(point - (Vector2.ONE / 2)) # ensure shape is centered |
|
|
|
|
|
|
|
|
|
|
|
# Add variations of the shape (rotated, mirrored), including the standard shape. |
|
|
|
# Add variations of the shape (rotated, mirrored), including the standard shape. |
|
|
|
for mirror in [ false, true ] if mirrored else [ false ]: |
|
|
|
for mirror in [ false, true ] if mirrored else [ false ]: |
|
|
|
for angle in [ 0, 90, 180, 270 ] if rotated else [ 0 ]: |
|
|
|
if mirror: |
|
|
|
var points := points_orig.duplicate() # transformed points |
|
|
|
# Mirror (flip) points along the X axis. |
|
|
|
# Technically we could skip `duplicate()` if not mirrored and not rotated, but eh. |
|
|
|
points = points.duplicate() |
|
|
|
|
|
|
|
for i in points.size(): |
|
|
|
if mirror: # Mirror (flip) points along the X axis. |
|
|
|
points[i] = points[i] * Transform2D.FLIP_X |
|
|
|
for i in points.size(): points[i] *= Transform2D.FLIP_X |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if angle != 0: # Rotate points around the center. |
|
|
|
for angle in [ 0, 90, 180, 270 ] if rotated else [ 0 ]: |
|
|
|
|
|
|
|
if angle != 0: |
|
|
|
|
|
|
|
# Rotate points around the center. |
|
|
|
var transform := Transform2D(deg_to_rad(angle), Vector2.ZERO) |
|
|
|
var transform := Transform2D(deg_to_rad(angle), Vector2.ZERO) |
|
|
|
for i in points.size(): points[i] *= transform |
|
|
|
points = points.duplicate() |
|
|
|
|
|
|
|
for i in points.size(): |
|
|
|
|
|
|
|
points[i] = points[i] * transform |
|
|
|
|
|
|
|
|
|
|
|
var shape_points: PackedVector2Array |
|
|
|
var shape_points: PackedVector2Array |
|
|
|
for point in points: shape_points.append(point * Block.SIZE) |
|
|
|
for point in points: shape_points.append(point * Block.SIZE) |
|
|
@ -130,17 +130,16 @@ class Layer extends StaticBody2D: |
|
|
|
@rpc("reliable") |
|
|
|
@rpc("reliable") |
|
|
|
func set_id_at(pos: Vector2i, id: int) -> void: |
|
|
|
func set_id_at(pos: Vector2i, id: int) -> void: |
|
|
|
var index := Chunk.array_index(pos) |
|
|
|
var index := Chunk.array_index(pos) |
|
|
|
if data[index] == id: return |
|
|
|
if data[index] != id: |
|
|
|
|
|
|
|
# TODO: Keep track of how many non-air blocks are present, to allow for cleaning empty chunks. |
|
|
|
|
|
|
|
data[index] = id |
|
|
|
|
|
|
|
chunk.dirty = true |
|
|
|
|
|
|
|
|
|
|
|
# TODO: Keep track of how many non-air blocks are present, to allow for cleaning empty chunks. |
|
|
|
|
|
|
|
data[index] = id |
|
|
|
|
|
|
|
chunk.dirty = true |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if multiplayer.is_server(): |
|
|
|
|
|
|
|
# Send change to every player tracking this chunk. |
|
|
|
# Send change to every player tracking this chunk. |
|
|
|
for player in chunk.get_players_tracking(): |
|
|
|
if multiplayer.is_server(): |
|
|
|
if player.network.is_local: continue # skip server player |
|
|
|
for player in chunk.get_players_tracking(): |
|
|
|
set_id_at.rpc_id(player.network.peer_id, pos, id) |
|
|
|
if player.network.is_local: continue # skip server player |
|
|
|
|
|
|
|
set_id_at.rpc_id(player.network.peer_id, pos, id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void: |
|
|
|
func _ready() -> void: |
|
|
@ -156,12 +155,14 @@ class Layer extends StaticBody2D: |
|
|
|
if child is CollisionShape2D: |
|
|
|
if child is CollisionShape2D: |
|
|
|
child.queue_free() |
|
|
|
child.queue_free() |
|
|
|
|
|
|
|
|
|
|
|
for pos in BlockRegion.LOCAL_CHUNK: |
|
|
|
for x in Chunk.SIZE: |
|
|
|
var shape := get_at(pos) |
|
|
|
for y in Chunk.SIZE: |
|
|
|
if shape.shape == null: continue |
|
|
|
var pos := Vector2i(x, y) |
|
|
|
|
|
|
|
var shape := get_at(pos) |
|
|
|
var shape2d := CollisionShape2D.new() |
|
|
|
if shape.shape == null: continue |
|
|
|
shape2d.name = "Block %s" % pos |
|
|
|
|
|
|
|
shape2d.position = (Vector2(pos) + (Vector2.ONE / 2)) * Block.SIZE - CHUNK_HALF_SIZE |
|
|
|
var shape2d := CollisionShape2D.new() |
|
|
|
shape2d.shape = shape.shape |
|
|
|
shape2d.name = "Block %s" % pos |
|
|
|
add_child(shape2d) |
|
|
|
shape2d.position = (Vector2(pos) + (Vector2.ONE / 2)) * Block.SIZE - CHUNK_HALF_SIZE |
|
|
|
|
|
|
|
shape2d.shape = shape.shape |
|
|
|
|
|
|
|
add_child(shape2d) |
|
|
|