summaryrefslogtreecommitdiffstats
path: root/world/chunk/ChunkGen.gd
blob: 0a94108918a04f1485f34c365b7b58caddec0d47 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
extends Node

onready var noise = OpenSimplexNoise.new()
onready var rng = RandomNumberGenerator.new()
var _seed

var monuments = []

func _ready():
    randomize()
    self._seed = randi()
    self.noise.seed = self._seed
    self.noise.seed = 0
    self.noise.period = 16
    self.noise.persistence = 0
    self.rng.seed = self._seed

func setup_monuments():
    monuments.push_back(lighthouseMonument.new(Transform(Basis(),Vector3(300.0,0.0,-300.0))))
    monuments.push_back(lighthouseMonument.new(Transform(Basis(),Vector3(0.0,0.0,-1000.0))))
    monuments.push_back(lighthouseMonument.new(Transform(Basis(),Vector3(-500.0,0.0,-2500.0))))
    monuments.push_back(DockMonument.new(Transform(Basis().rotated(Vector3.UP,PI/2.0),Vector3(-500.0,0.0,0.0))))

func rng_2dv(coords:Vector2):
    self.rng.seed = hash(coords)

func gen_chunk(chunk,dummy=false):
    if dummy:
        return
    var monument = get_monument_at_chunk(ChunkLoader.v2_coords(chunk.transform.origin))
    if monument != null:
        gen_monument(chunk, monument)
    else:
        gen_distance(chunk,chunk.get_node("gen_tree/lod_distance"))
        gen_mid(chunk,chunk.get_node("gen_tree/lod_mid"))
        gen_close(chunk,chunk.get_node("gen_tree/lod_close"))

func get_monument_at_chunk(chunk_coords:Vector2):
    for monument in monuments:
        if monument.is_chunk_in_monument(chunk_coords):
            return monument
    return null

func gen_monument(chunk, monument):
    var inst = monument.scene.instance()
    var offset_to_origin = monument.xform.origin - chunk.transform.origin
    inst.transform.origin = offset_to_origin
    inst.transform.basis = monument.xform.basis
    chunk.add_child(inst)

func gen_distance(chunk,tree):
    gen_lowres_rocks(chunk,tree)

func gen_mid(chunk,tree):
    gen_rocks(chunk,tree)

func gen_close(chunk,tree):
    gen_rock_hitboxes(chunk,tree)

func iterate_chunk(chunk,tree,step:Vector2,cb:FuncRef,data):
    var chunk_half_size = ChunkLoader.world.chunk_half_size
    var chunk_size_rounded = Vector2(chunk_half_size,chunk_half_size).snapped(step)
    for x in range(-chunk_size_rounded.x,chunk_size_rounded.x,step.x):
        for y in range(-chunk_size_rounded.y,chunk_size_rounded.y,step.y):
            cb.call_func(chunk,tree,Vector2(x,y),data)

func make_multimesh(name,cnt,mesh):
    var multi_inst = MultiMeshInstance.new()
    multi_inst.name = name
    var multi = MultiMesh.new()
    multi_inst.multimesh = multi
    multi.transform_format = MultiMesh.TRANSFORM_3D
    multi.mesh = mesh
    multi.instance_count = cnt
    multi.visible_instance_count = 0
    return multi_inst

var rock1_mesh = preload("res://world/obstacles/rock/rock_1.obj")
var rock2_mesh = preload("res://world/obstacles/rock/rock_2.obj")
var rock3_mesh = preload("res://world/obstacles/rock/rock_3.obj")
var rock4_mesh = preload("res://world/obstacles/rock/rock_4.obj")
var rock_mat = preload("res://world/obstacles/rock/rock_material.tres")
func gen_rocks(chunk,tree):
    var rocks1 = make_multimesh("rocks1",100,rock1_mesh)
    var rocks2 = make_multimesh("rocks2",100,rock2_mesh)
    var rocks3 = make_multimesh("rocks3",100,rock3_mesh)
    var rocks4 = make_multimesh("rocks4",100,rock4_mesh)
    rocks1.material_override = rock_mat
    rocks2.material_override = rock_mat
    rocks3.material_override = rock_mat
    rocks4.material_override = rock_mat
    tree.add_child(rocks1)
    tree.add_child(rocks2)
    tree.add_child(rocks3)
    tree.add_child(rocks4)
    iterate_chunk(chunk, rocks1.multimesh, Vector2(10.0,10.0), funcref(self,"rock_rng"), [1,funcref(self,"make_rock")])
    iterate_chunk(chunk, rocks2.multimesh, Vector2(10.0,10.0), funcref(self,"rock_rng"), [3,funcref(self,"make_rock")])
    iterate_chunk(chunk, rocks3.multimesh, Vector2(10.0,10.0), funcref(self,"rock_rng"), [4,funcref(self,"make_rock")])
    iterate_chunk(chunk, rocks4.multimesh, Vector2(10.0,10.0), funcref(self,"rock_rng"), [2,funcref(self,"make_rock")])

var rock_lowres_mesh = preload("res://world/obstacles/rock/rock_lowres_mesh.tres")
func gen_lowres_rocks(chunk,tree):
    rock_lowres_mesh.material = rock_mat
    var multi = make_multimesh("rocks",50,rock_lowres_mesh)
    tree.add_child(multi)
    iterate_chunk(chunk, multi.multimesh, Vector2(20.0,20.0), funcref(self,"rock_rng"), [0,funcref(self,"make_rock")])

var rock_coll = preload("res://world/obstacles/rock/rock_collision.tres")
func gen_rock_hitboxes(chunk,tree):
    iterate_chunk(chunk, tree, Vector2(20.0,20.0), funcref(self,"rock_rng"), [0,funcref(self,"make_rock_hitbox")])

func rock_rng(chunk,rocks,chunk_coords:Vector2,data):
    var coords = ChunkLoader.v3_coords(chunk_coords)
    var basis = Basis()

    var world_coords = chunk_coords + ChunkLoader.v2_coords(chunk.transform.origin)
    self.rng_2dv(world_coords)
    var noise_val = self.noise.get_noise_2dv(world_coords * 0.125)

    #threshold to generate a rock
    var noise_min_pointy = 0.4
    var noise_max_pointy = 0.5
    var noise_max_round = 0.7

    if noise_val < noise_min_pointy:
        return

    var rock = self.rng.randi_range(1,4)
    #choose a rock
    if data[0] != 0:
        if noise_val <= noise_max_pointy:
            if rock != data[0]:
                return
        else:
            if ((rock%2)+1) != data[0]:
                return

    #normalize noise from 0.0 to 1.0
    noise_val = min(noise_val,noise_max_round)
    noise_val -= noise_min_pointy
    noise_val /= noise_max_round - noise_min_pointy

    #random rotation
    var rng_val = self.rng.randf_range(0.0,TAU)
    basis = Basis(Vector3.UP,rng_val) * basis

    #scale based on noise
    var scale_min = 0.167
    var scale_max = 0.667
    var scale = lerp(scale_min,scale_max,noise_val)
    basis = basis.scaled(Vector3.ONE*scale)

    #scale the pointy rocks taller
    if rock == 3 || rock == 4:
        rng_val = self.rng.randf_range(1.0,1.25)
        scale = rng_val * scale
        basis = basis.scaled(Vector3(1.0,rng_val,1.0))

    #normalize height
    match rock:
        0:
            coords.y += 30.0 * scale
        1:
            coords.y += 31.5 * scale
        2:
            coords.y += 27.5 * scale
        3:
            coords.y += 42.5 * scale
        4:
            coords.y += 40.0 * scale

    #shift them all slightly down
    coords.y -= 5.0

    data[1].call_func(rocks,Transform(basis,coords))

func make_rock(rocks,xform:Transform):
    rocks.visible_instance_count += 1
    rocks.set_instance_transform(rocks.visible_instance_count-1, xform)

func make_rock_hitbox(rocks,xform:Transform):
    var shape = CollisionShape.new()
    shape.shape = rock_coll
    shape.transform = xform
    rocks.add_child(shape)