Add files via upload
25
README.md
|
@ -1 +1,24 @@
|
||||||
# Godot-Voxel-Prototype
|
# Voxel Prototype
|
||||||
|
|
||||||
|
# Licenses: code: LGPL-2.1, media: CC BY-SA-4.0
|
||||||
|
## this is a Godot game project: https://godotengine.org
|
||||||
|
|
||||||
|
![Screenshot](/screenshot.PNG)
|
||||||
|
|
||||||
|
**Notes**
|
||||||
|
|
||||||
|
1. i like to do things simple, the result is more performance + a less confused coder.
|
||||||
|
1. this was a very early step in my game progress.
|
||||||
|
1. i dont know why the water looks wierd.
|
||||||
|
1. i dont know why the player is shaking.
|
||||||
|
1. i have no desire to make a save game system or update this project anymore.
|
||||||
|
1. just enyoy
|
||||||
|
|
||||||
|
|Action|Control|
|
||||||
|
|----|----|
|
||||||
|
|Move|A,S,D,W,S|
|
||||||
|
|Jump|Space|
|
||||||
|
Fly/Walk mode|F|
|
||||||
|
Fly up/down|Q,E|
|
||||||
|
Fly slow|SHIFT|
|
||||||
|
Choose block|scroll up/down|
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
extends Spatial
|
||||||
|
|
||||||
|
var timer = 0
|
||||||
|
var chunks_in_progress = {}
|
||||||
|
var progress2del = {}
|
||||||
|
|
||||||
|
func _init():
|
||||||
|
core.chunk=self
|
||||||
|
|
||||||
|
#creates a new chunk array
|
||||||
|
#adds air to it so the player not reaching a empty space and things craches
|
||||||
|
func new_chunk(pos):
|
||||||
|
var id = pos_to_chunkid(pos)
|
||||||
|
var chunk_pos = to_chunk_pos(pos)
|
||||||
|
var air = core.get_node_reg("air").id
|
||||||
|
for x in range(-core.chunk_size/2,core.chunk_size/2):
|
||||||
|
for y in range(-core.chunk_size/2,core.chunk_size/2):
|
||||||
|
for z in range(-core.chunk_size/2,core.chunk_size/2):
|
||||||
|
core.inset_map_node_id(air,chunk_pos+Vector3(x,y,z))
|
||||||
|
core.chunks[id] = MeshInstance.new()
|
||||||
|
var chunk = core.chunks[id]
|
||||||
|
chunk.transform.origin = chunk_pos
|
||||||
|
add_child(chunk)
|
||||||
|
var staticbody = StaticBody.new()
|
||||||
|
staticbody.name = "body"
|
||||||
|
chunk.add_child(staticbody)
|
||||||
|
var collision = CollisionShape.new()
|
||||||
|
collision.name = "collision"
|
||||||
|
staticbody.add_child(collision)
|
||||||
|
|
||||||
|
func to_chunk_pos(pos):
|
||||||
|
var c = core.chunk_size
|
||||||
|
var s = core.chunk_size/2
|
||||||
|
return ((pos+Vector3(s,s,s))/c).floor()*c
|
||||||
|
|
||||||
|
func get_chunk_at_pos(pos):
|
||||||
|
var c = core.chunk_size
|
||||||
|
var s = core.chunk_size/2
|
||||||
|
var c_pos = ((pos+Vector3(s,s,s))/c).floor()
|
||||||
|
return core.chunks.get(c_pos)
|
||||||
|
|
||||||
|
func pos_to_chunkid(pos):
|
||||||
|
var c = core.chunk_size
|
||||||
|
var s = core.chunk_size/2
|
||||||
|
return ((pos+Vector3(s,s,s))/c).floor()
|
||||||
|
|
||||||
|
func get_chunk(id):
|
||||||
|
return core.chunks.get(id)
|
||||||
|
|
||||||
|
#sends chunks to update in a list to process
|
||||||
|
#this keeps performance well, even we can expect somewhat slower loading
|
||||||
|
func _process(delta):
|
||||||
|
timer += delta
|
||||||
|
if timer > 0.0:
|
||||||
|
timer = 0
|
||||||
|
|
||||||
|
for i in progress2del:
|
||||||
|
chunks_in_progress.erase(i)
|
||||||
|
progress2del.clear()
|
||||||
|
var max_nodes = core.settings.max_update_nodes
|
||||||
|
for di in chunks_in_progress:
|
||||||
|
var data = chunks_in_progress.get(di)
|
||||||
|
var chunk_mesh = get_chunk(data.chunkid)
|
||||||
|
for x in range(data.range_x.a,data.range_x.b):
|
||||||
|
for y in range(data.range_y.a,data.range_y.b):
|
||||||
|
for z in range(data.range_z.a,data.range_z.b):
|
||||||
|
|
||||||
|
max_nodes -= 1
|
||||||
|
if max_nodes < 0:
|
||||||
|
data.range_x.a = x
|
||||||
|
data.range_y.a = y
|
||||||
|
data.range_z.a = z
|
||||||
|
return
|
||||||
|
|
||||||
|
var lpos = Vector3(x,y,z)
|
||||||
|
var id = core.map.get(lpos+data.chunk_pos)
|
||||||
|
|
||||||
|
if id:
|
||||||
|
var n = core.register.id.get(id) if id != null else "default"
|
||||||
|
var reg = core.register.nodes.get(n)
|
||||||
|
var tile = core.default_texture if reg.tiles.size() < 1 else reg.tiles[0]
|
||||||
|
if reg.drawtype != "none":
|
||||||
|
for f in core.default_node.faces.size():
|
||||||
|
var neighbour_id = core.map.get(lpos+core.default_node.dir[f]+data.chunk_pos)
|
||||||
|
var neighbour_name = core.register.id.get(neighbour_id) if neighbour_id != null else "none"
|
||||||
|
var neighbour_reg = core.register.nodes.get(neighbour_name)
|
||||||
|
|
||||||
|
if (data.full_cubes and neighbour_id == null) or (neighbour_id != id and neighbour_reg.get("solid_surface") == false):
|
||||||
|
data.st.begin(Mesh.PRIMITIVE_TRIANGLE_FAN)
|
||||||
|
var mat = SpatialMaterial.new()
|
||||||
|
var transparent = reg.get("transparent") == true
|
||||||
|
if f < reg.tiles.size():
|
||||||
|
tile = reg.tiles[f]
|
||||||
|
mat.albedo_texture = tile
|
||||||
|
mat.flags_transparent = transparent
|
||||||
|
data.st.set_material(mat)
|
||||||
|
data.st.add_color(Color(0,1,1))
|
||||||
|
var cmf = []
|
||||||
|
for v in range(0,4):
|
||||||
|
data.st.add_uv(core.default_node.uv[v])
|
||||||
|
data.st.add_vertex(core.default_node.faces[f][v]+lpos)
|
||||||
|
cmf.push_back(core.default_node.faces[f][v]+lpos)
|
||||||
|
|
||||||
|
data.st.commit(data.mesh)
|
||||||
|
# the faces is added, now add to the collision
|
||||||
|
# the TRIANGLE_FAN allows us to be more flexible models, but the trimesh do not work with it
|
||||||
|
# so we are using TRIANGLES for that
|
||||||
|
if reg.get("collidable") != false:
|
||||||
|
data.cst.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||||
|
data.cst.add_triangle_fan(cmf)
|
||||||
|
data.cst.commit(data.collision_mesh)
|
||||||
|
data.st.clear()
|
||||||
|
data.cst.clear()
|
||||||
|
chunk_mesh.mesh = data.mesh
|
||||||
|
chunk_mesh.get_node_or_null("body/collision").shape = data.collision_mesh.create_trimesh_shape()
|
||||||
|
chunks_in_progress.erase(di)
|
||||||
|
progress2del[di] = di
|
||||||
|
# the chunk is done, now work on next update
|
||||||
|
func update(pos):
|
||||||
|
if get_chunk_at_pos(pos) == null:
|
||||||
|
new_chunk(pos)
|
||||||
|
#no chunk here, generate it quickly
|
||||||
|
core.current_mapgen.call_func(to_chunk_pos(pos))
|
||||||
|
return
|
||||||
|
|
||||||
|
var chunkid = pos_to_chunkid(pos)
|
||||||
|
var data = {
|
||||||
|
vertex = {},
|
||||||
|
full_cubes = core.settings.full_3d_cubes,
|
||||||
|
mesh = Mesh.new(),
|
||||||
|
collision_mesh = Mesh.new(),
|
||||||
|
chunkid = chunkid,
|
||||||
|
chunk_pos = get_chunk(chunkid).transform.origin,
|
||||||
|
st = SurfaceTool.new(),
|
||||||
|
cst = SurfaceTool.new(),
|
||||||
|
range_x = {a=-core.chunk_size/2,b=core.chunk_size/2},
|
||||||
|
range_y = {a=-core.chunk_size/2,b=core.chunk_size/2},
|
||||||
|
range_z = {a=-core.chunk_size/2,b=core.chunk_size/2},
|
||||||
|
}
|
||||||
|
chunks_in_progress[chunkid] = data
|
|
@ -0,0 +1,7 @@
|
||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://chunk.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="chunks" type="Spatial"]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0.5, -0.5 )
|
||||||
|
script = ExtResource( 1 )
|
|
@ -0,0 +1,125 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var chunk #noderef functions
|
||||||
|
var chunks = {} #contains all chucks, using Vector3() as keys or "id"
|
||||||
|
var chunk_size=8#16 are more common for this kind of game, but is 4X slower to update
|
||||||
|
|
||||||
|
var default_texture = load("res://res/stone.png")#used if we are unable to get the nodes tiles
|
||||||
|
var player = {name="singleplayer",object=null,inventory=["stone","dirt","grassy","water_source"],inventory_index=0}
|
||||||
|
var map = {}#contains all nodes, using Vector3() as keys or "id", contains a number/node id, strings would use too much memory
|
||||||
|
var collision_map = {}
|
||||||
|
var settings = {
|
||||||
|
full_3d_cubes=false,
|
||||||
|
update_chunk_rules=[Vector3(-1,0,0),Vector3(1,0,0),Vector3(0,0,-1),Vector3(0,0,1),Vector3(0,-1,0),Vector3(0,1,0)],
|
||||||
|
ganerate_chunk_range=4,
|
||||||
|
max_update_nodes=512,
|
||||||
|
}
|
||||||
|
var default_node_id = 7
|
||||||
|
var mapgen = {}
|
||||||
|
var current_mapgen # funcref
|
||||||
|
var register = {
|
||||||
|
nodes = {
|
||||||
|
none={id=0,name="none",drawtype="none",tiles=[]},
|
||||||
|
air={id=1,name="air",drawtype="none",tiles=[],collidable=false,solid_surface=false},
|
||||||
|
stone={id=2,name="stone",drawtype="default",tiles=[load("res://res/stone.png")]},
|
||||||
|
grassy={id=3,name="grassy",drawtype="default",tiles=[
|
||||||
|
load("res://res/grass.png"),
|
||||||
|
load("res://res/dirt.png"),
|
||||||
|
load("res://res/grass_dirt.png"),
|
||||||
|
load("res://res/grass_dirt.png"),
|
||||||
|
load("res://res/grass_dirt.png"),
|
||||||
|
load("res://res/grass_dirt.png"),
|
||||||
|
]},
|
||||||
|
dirt={id=4,name="dirt",drawtype="default",tiles=[load("res://res/dirt.png")]},
|
||||||
|
water_source={id=5,name="water_source",replaceable=true,drawtype="liquid",collidable=false,transparent=true,solid_surface=false,tiles=[load("res://res/water.png")]},
|
||||||
|
},
|
||||||
|
id = {0:"none",1:"air",2:"stone",3:"grassy",4:"dirt",5:"water_source"},
|
||||||
|
}
|
||||||
|
var default_node = {
|
||||||
|
uv = [Vector2(0,0),Vector2(0,1),Vector2(1,1),Vector2(1,0)],
|
||||||
|
dir = [Vector3(0,1,0),Vector3(0,-1,0),Vector3(1,0,0),Vector3(-1,0,0),Vector3(0,0,-1),Vector3(0,0,1)],
|
||||||
|
faces = [
|
||||||
|
[Vector3(1,0,0),Vector3(1,0,1),Vector3(0,0,1),Vector3(0,0,0)], #up y+
|
||||||
|
[Vector3(0,-1,0),Vector3(0,-1,1),Vector3(1,-1,1),Vector3(1,-1,0)], #down y-
|
||||||
|
[Vector3(1,0,0),Vector3(1,-1,0),Vector3(1,-1,1),Vector3(1,0,1)], #north x+
|
||||||
|
[Vector3(0,0,1),Vector3(0,-1,1),Vector3(0,-1,0),Vector3(0,0,0)], #south x-
|
||||||
|
[Vector3(0,0,0),Vector3(0,-1,0),Vector3(1,-1,0),Vector3(1,0,0)], #east z+
|
||||||
|
[Vector3(1,0,1),Vector3(1,-1,1),Vector3(0,-1,1),Vector3(0,0,1)], #west z-
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
#returns name of node you are pointing at, pos would be more usefull i think
|
||||||
|
#use the penultimate pos to get the node next to it
|
||||||
|
func pointed_at_node():
|
||||||
|
var pos = player.object.get_translation()
|
||||||
|
var aim = player.object.get_node("head/Camera").get_global_transform().basis
|
||||||
|
var hpos = player.object.get_node("head").get_translation()
|
||||||
|
for i in range(-1,-500,-1):
|
||||||
|
var p = (pos + hpos+(aim.z*Vector3(i*0.01,i*0.01,i*0.01)))#.round()
|
||||||
|
var rp = p.round()
|
||||||
|
var id = map.get(rp)
|
||||||
|
var reg = get_node_reg(id)
|
||||||
|
if reg != null and reg.get("drawtype") != "none" and reg.get("collidable") != false:
|
||||||
|
if (p.x >= rp.x-0.5 and p.x <= rp.x+0.5) and (p.y >= rp.y-0.5 and p.y <= rp.y+0.5) and (p.z >= rp.z-0.5 and p.z <= rp.z+0.5):
|
||||||
|
return reg.name
|
||||||
|
return "none"
|
||||||
|
|
||||||
|
|
||||||
|
#problity you finds a better way to use this
|
||||||
|
#but this is what i used while testing
|
||||||
|
func pointed_node_action(n):
|
||||||
|
var pos = player.object.get_translation()
|
||||||
|
var aim = player.object.get_node("head/Camera").get_global_transform().basis
|
||||||
|
var hpos = player.object.get_node("head").get_translation()
|
||||||
|
var lpos = (pos + hpos+aim.z).round()
|
||||||
|
|
||||||
|
for i in range(-1,-500,-1):
|
||||||
|
var p = (pos + hpos+(aim.z*Vector3(i*0.01,i*0.01,i*0.01)))#.round()
|
||||||
|
var rp = p.round()
|
||||||
|
var id = map.get(rp)
|
||||||
|
|
||||||
|
|
||||||
|
if id and id != 1:
|
||||||
|
if core.chunk.get_chunk_at_pos(rp):
|
||||||
|
if (p.x >= rp.x-0.5 and p.x <= rp.x+0.5) and (p.y >= rp.y-0.5 and p.y <= rp.y+0.5) and (p.z >= rp.z-0.5 and p.z <= rp.z+0.5):
|
||||||
|
var node = player.inventory[player.inventory_index] if n == 0 else "air"
|
||||||
|
var pp = rp
|
||||||
|
if n == 0:
|
||||||
|
var Name = register.id[id]
|
||||||
|
var reg = register.nodes[Name]
|
||||||
|
pp = rp if reg.get("replaceable") == true else lpos
|
||||||
|
set_node({name=node,pos=pp})
|
||||||
|
return
|
||||||
|
lpos = rp
|
||||||
|
|
||||||
|
func get_node_reg(v):#a flexible way to get node properties by pos, id or name
|
||||||
|
if v is Vector3:
|
||||||
|
v = v.round()
|
||||||
|
v = map.get(v)
|
||||||
|
elif v is String:
|
||||||
|
return register.nodes.get(v)
|
||||||
|
var n = register.id.get(v)
|
||||||
|
return register.nodes.get(n)
|
||||||
|
|
||||||
|
func get_node(pos):#returns node id
|
||||||
|
assert(typeof(pos) == TYPE_VECTOR3,"ERROR: set_node: pos required!")
|
||||||
|
return map.get(pos)
|
||||||
|
|
||||||
|
func set_node(def:Dictionary):# set node
|
||||||
|
assert(typeof(def.get("pos")) == TYPE_VECTOR3 and typeof(def.get("name")) == TYPE_STRING,"ERROR: set_node: def.pos & def.name required!")
|
||||||
|
var n = register.nodes.get(def.name)
|
||||||
|
assert(n != null,str('ERROR: set_node: "',def.name,'"', " doesn't exists"))
|
||||||
|
var rpos = def.pos.round()
|
||||||
|
map[rpos] = get_node_reg(def.name).id
|
||||||
|
|
||||||
|
#check if chunks around the node need to be updated
|
||||||
|
var cid = chunk.pos_to_chunkid(rpos)
|
||||||
|
for r in settings.update_chunk_rules.size():
|
||||||
|
var near_chunk = rpos+settings.update_chunk_rules[r]
|
||||||
|
if chunk.pos_to_chunkid(near_chunk) != cid:
|
||||||
|
chunk.update(near_chunk)
|
||||||
|
#check the chunk
|
||||||
|
chunk.update(rpos)
|
||||||
|
|
||||||
|
func inset_map_node_id(id,pos):# easyer to use
|
||||||
|
map[pos] = id
|
|
@ -0,0 +1,7 @@
|
||||||
|
[gd_resource type="Environment" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSky" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
background_mode = 2
|
||||||
|
background_sky = SubResource( 1 )
|
|
@ -0,0 +1,19 @@
|
||||||
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://player.tscn" type="PackedScene" id=1]
|
||||||
|
[ext_resource path="res://chunk.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id=1]
|
||||||
|
background_mode = 1
|
||||||
|
background_color = Color( 0.447059, 0.666667, 0.858824, 1 )
|
||||||
|
ambient_light_color = Color( 1, 1, 1, 1 )
|
||||||
|
|
||||||
|
[node name="main" type="Spatial"]
|
||||||
|
|
||||||
|
[node name="chunks" parent="." instance=ExtResource( 2 )]
|
||||||
|
|
||||||
|
[node name="player" parent="." instance=ExtResource( 1 )]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
|
environment = SubResource( 1 )
|
|
@ -0,0 +1,72 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var timer = 1
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
core.current_mapgen = funcref(self,"super_flatland")
|
||||||
|
yield(get_tree().create_timer(2),"timeout")
|
||||||
|
for x in range(-4,4):
|
||||||
|
for z in range(-4,4):
|
||||||
|
core.inset_map_node_id(5,Vector3(x,0,z))
|
||||||
|
core.chunk.update(Vector3(0,0,0))
|
||||||
|
|
||||||
|
var n2gc_timer = -0.01
|
||||||
|
var n2gc_time = 0
|
||||||
|
func _process(delta):
|
||||||
|
timer += delta
|
||||||
|
if timer > n2gc_time:
|
||||||
|
if n2gc_timer >= 1:
|
||||||
|
n2gc_timer = 0
|
||||||
|
n2gc_time = 1
|
||||||
|
else:
|
||||||
|
n2gc_timer += timer
|
||||||
|
timer = 0
|
||||||
|
|
||||||
|
var ppos = core.player.object.global_transform.origin
|
||||||
|
|
||||||
|
var pos = core.chunk.to_chunk_pos(ppos)
|
||||||
|
if core.chunk.get_chunk_at_pos(pos) == null:
|
||||||
|
core.chunk.new_chunk(pos)
|
||||||
|
core.current_mapgen.call_func(pos)
|
||||||
|
n2gc_time = 0
|
||||||
|
n2gc_timer = 0
|
||||||
|
#return
|
||||||
|
for i in range(1,core.settings.ganerate_chunk_range):
|
||||||
|
var r = core.chunk_size*i
|
||||||
|
var s = core.chunk_size
|
||||||
|
for x in range(-r,r,s):
|
||||||
|
for y in range(-r,r,s):
|
||||||
|
for z in range(-r,r,s):
|
||||||
|
pos = Vector3(x,y,z) + core.chunk.to_chunk_pos(ppos)
|
||||||
|
if core.chunk.get_chunk_at_pos(pos) == null:
|
||||||
|
core.chunk.new_chunk(pos)
|
||||||
|
core.current_mapgen.call_func(pos)
|
||||||
|
n2gc_time = 0
|
||||||
|
n2gc_timer = 0
|
||||||
|
|
||||||
|
#generates a flat map:
|
||||||
|
#all nodes above 9 will be air
|
||||||
|
#0 = grassy
|
||||||
|
#-1 - -3 = dirt
|
||||||
|
#-4 and lower = stone
|
||||||
|
func super_flatland(pos):
|
||||||
|
var id
|
||||||
|
var grassy = core.get_node_reg("grassy").id
|
||||||
|
var dirt = core.get_node_reg("dirt").id
|
||||||
|
var stone = core.get_node_reg("stone").id
|
||||||
|
var air = core.get_node_reg("air").id
|
||||||
|
var Y
|
||||||
|
for x in range(-core.chunk_size/2,core.chunk_size/2):
|
||||||
|
for y in range(-core.chunk_size/2,core.chunk_size/2):
|
||||||
|
for z in range(-core.chunk_size/2,core.chunk_size/2):
|
||||||
|
Y = pos.y+y
|
||||||
|
if Y == 0:
|
||||||
|
id = grassy
|
||||||
|
elif Y < -3:
|
||||||
|
id = stone
|
||||||
|
elif Y < 0:
|
||||||
|
id = dirt
|
||||||
|
else:
|
||||||
|
id = air
|
||||||
|
core.inset_map_node_id(id,Vector3(x,y,z)+pos)
|
||||||
|
core.chunk.update(pos)
|
|
@ -0,0 +1,94 @@
|
||||||
|
extends KinematicBody
|
||||||
|
|
||||||
|
var direction = Vector3()
|
||||||
|
var velocity = Vector3()
|
||||||
|
var gravity = -27
|
||||||
|
var jump_height = 10
|
||||||
|
var walk_speed = 10
|
||||||
|
var fpv_camera_angle = 0
|
||||||
|
var fpv_mouse_sensitivity = 0.3
|
||||||
|
var fly_mode = false
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
core.player.object = self
|
||||||
|
|
||||||
|
#camera
|
||||||
|
func _input(event):
|
||||||
|
if Input.is_action_just_pressed("ui_cancel"):
|
||||||
|
get_tree().quit()
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
rotate_y(deg2rad(-event.relative.x * fpv_mouse_sensitivity))
|
||||||
|
var change = -event.relative.y * fpv_mouse_sensitivity
|
||||||
|
if change + fpv_camera_angle < 90 and change + fpv_camera_angle > -90:
|
||||||
|
$head/Camera.rotate_x(deg2rad(change))
|
||||||
|
fpv_camera_angle += change
|
||||||
|
elif event is InputEventMouseButton:
|
||||||
|
if Input.is_action_just_pressed("LMB"):
|
||||||
|
core.pointed_node_action(0)
|
||||||
|
elif Input.is_action_just_pressed("RMB"):
|
||||||
|
core.pointed_node_action(1)
|
||||||
|
elif Input.is_action_just_pressed("WHEEL_UP"):
|
||||||
|
core.player.inventory_index += 1
|
||||||
|
if core.player.inventory_index >= core.player.inventory.size():
|
||||||
|
core.player.inventory_index = 0
|
||||||
|
elif Input.is_action_just_pressed("WHEEL_DOWN"):
|
||||||
|
core.player.inventory_index -= 1
|
||||||
|
if core.player.inventory_index <= 0:
|
||||||
|
core.player.inventory_index = core.player.inventory.size()-1
|
||||||
|
# moving
|
||||||
|
func _process(delta):
|
||||||
|
direction = Vector3()
|
||||||
|
var aim = $head/Camera.get_global_transform().basis
|
||||||
|
var pos = transform.origin
|
||||||
|
var con = Vector3()
|
||||||
|
if Input.is_key_pressed(KEY_W):
|
||||||
|
con -= aim.z
|
||||||
|
if Input.is_key_pressed(KEY_S):
|
||||||
|
con += aim.z
|
||||||
|
if Input.is_key_pressed(KEY_A):
|
||||||
|
con -= aim.x
|
||||||
|
if Input.is_key_pressed(KEY_D):
|
||||||
|
con += aim.x
|
||||||
|
if Input.is_action_just_pressed("fly_mode"):
|
||||||
|
fly_mode = fly_mode == false
|
||||||
|
$Collision.disabled = fly_mode
|
||||||
|
velocity = Vector3(0,0,0)
|
||||||
|
#this lines just updates the screen info
|
||||||
|
#if you are not trying to solve a problem, this 4 lines is kinda useless, and useing unnecessarily performance
|
||||||
|
ui.screeninfo("player_pos",transform.origin)
|
||||||
|
ui.screeninfo("chunk_id",core.chunk.pos_to_chunkid(transform.origin))
|
||||||
|
ui.screeninfo("chunk_pos",core.chunk.to_chunk_pos(transform.origin))
|
||||||
|
ui.screeninfo("pointing_at",core.pointed_at_node())
|
||||||
|
|
||||||
|
|
||||||
|
if fly_mode:
|
||||||
|
if Input.is_key_pressed(KEY_E):
|
||||||
|
con.y += 1
|
||||||
|
if Input.is_key_pressed(KEY_Q):
|
||||||
|
con.y -= 1
|
||||||
|
if Input.is_key_pressed(KEY_SHIFT):
|
||||||
|
con*=0.1
|
||||||
|
transform.origin += con*0.2
|
||||||
|
else:
|
||||||
|
var on_floor = is_on_floor()
|
||||||
|
direction = con
|
||||||
|
direction = direction.normalized()
|
||||||
|
if on_floor:
|
||||||
|
velocity.y = 0
|
||||||
|
else:
|
||||||
|
#if player is inside a collidable block, freeze the movement to prevent falling through the ground
|
||||||
|
var id = core.map.get(pos.round())
|
||||||
|
var n = core.register.id.get(id) if id != null else "default"
|
||||||
|
var reg = core.register.nodes.get(n)
|
||||||
|
if reg.get("collidable") != false:
|
||||||
|
velocity.y = 0
|
||||||
|
return
|
||||||
|
velocity.y += gravity * delta
|
||||||
|
var tv = velocity
|
||||||
|
tv = velocity.linear_interpolate(direction * walk_speed,15 * delta)
|
||||||
|
velocity.x = tv.x
|
||||||
|
velocity.z = tv.z
|
||||||
|
velocity = move_and_slide(velocity,Vector3(0,1,0))
|
||||||
|
# == jumping
|
||||||
|
if on_floor and Input.is_key_pressed(KEY_SPACE):
|
||||||
|
velocity.y = jump_height
|
|
@ -0,0 +1,27 @@
|
||||||
|
[gd_scene load_steps=5 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://player.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[sub_resource type="CubeMesh" id=1]
|
||||||
|
|
||||||
|
[sub_resource type="SpatialMaterial" id=2]
|
||||||
|
albedo_color = Color( 1, 0, 0, 1 )
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape" id=3]
|
||||||
|
|
||||||
|
[node name="player" type="KinematicBody"]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[node name="mesh" type="MeshInstance" parent="."]
|
||||||
|
transform = Transform( 0.4, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
|
||||||
|
mesh = SubResource( 1 )
|
||||||
|
material/0 = SubResource( 2 )
|
||||||
|
|
||||||
|
[node name="Collision" type="CollisionShape" parent="."]
|
||||||
|
transform = Transform( 0.4, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
|
||||||
|
shape = SubResource( 3 )
|
||||||
|
|
||||||
|
[node name="head" type="Spatial" parent="."]
|
||||||
|
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0 )
|
||||||
|
|
||||||
|
[node name="Camera" type="Camera" parent="head"]
|
|
@ -0,0 +1,84 @@
|
||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Voxel Prototype"
|
||||||
|
run/main_scene="res://main.tscn"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[autoload]
|
||||||
|
|
||||||
|
core="*res://core.gd"
|
||||||
|
mapgen="*res://mapgen.gd"
|
||||||
|
ui="*res://ui.tscn"
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/stretch/mode="viewport"
|
||||||
|
|
||||||
|
[importer_defaults]
|
||||||
|
|
||||||
|
texture={
|
||||||
|
"compress/bptc_ldr": 0,
|
||||||
|
"compress/hdr_mode": 0,
|
||||||
|
"compress/lossy_quality": 0.7,
|
||||||
|
"compress/mode": 2,
|
||||||
|
"compress/normal_map": 0,
|
||||||
|
"detect_3d": false,
|
||||||
|
"flags/anisotropic": false,
|
||||||
|
"flags/filter": false,
|
||||||
|
"flags/mipmaps": true,
|
||||||
|
"flags/repeat": true,
|
||||||
|
"flags/srgb": 1,
|
||||||
|
"process/HDR_as_SRGB": false,
|
||||||
|
"process/fix_alpha_border": false,
|
||||||
|
"process/invert_color": false,
|
||||||
|
"process/premult_alpha": false,
|
||||||
|
"size_limit": 0,
|
||||||
|
"stream": false,
|
||||||
|
"svg/scale": 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
fly_mode={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":70,"unicode":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
LMB={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
RMB={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":2,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
WHEEL_UP={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
WHEEL_DOWN={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
[physics]
|
||||||
|
|
||||||
|
common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
environment/default_environment="res://default_env.tres"
|
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 862 B |
After Width: | Height: | Size: 676 B |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 185 KiB |
|
@ -0,0 +1,29 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
var _screeninfo = {
|
||||||
|
player_pos = Vector3(),
|
||||||
|
chunk_id = Vector3(),
|
||||||
|
chunk_pos = Vector3(),
|
||||||
|
pointing_at = "",
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
|
var ss = get_viewport_rect().size/2
|
||||||
|
var cs = $crosshair.rect_size / 2
|
||||||
|
$crosshair.rect_position = ss - cs
|
||||||
|
|
||||||
|
var p = OS.get_screen_size()/2
|
||||||
|
var s = OS.window_size/2
|
||||||
|
var winpos = p-s
|
||||||
|
winpos.y = 0 #now we can see the output
|
||||||
|
OS.set_window_position(winpos)
|
||||||
|
|
||||||
|
#if you are not trying to solve a problem, this one is kinda useless
|
||||||
|
func screeninfo(lab,v):
|
||||||
|
_screeninfo[lab] = v
|
||||||
|
var s = _screeninfo.player_pos.round()
|
||||||
|
var c = _screeninfo.chunk_id
|
||||||
|
var p = _screeninfo.chunk_pos
|
||||||
|
$screeninfo.text = str("Pos: ",s.x,",",s.y,",",s.z," Chunk ID: ",c.x,",",c.y,",",c.z," Chunk pos: ",p.x,",",p.y,",",p.z," Pointing at: ",_screeninfo.pointing_at)
|
|
@ -0,0 +1,30 @@
|
||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://ui.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://res/crosshair.png" type="Texture" id=2]
|
||||||
|
|
||||||
|
[node name="ui" type="Control"]
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="crosshair" type="TextureRect" parent="."]
|
||||||
|
margin_left = 60.1041
|
||||||
|
margin_top = 207.182
|
||||||
|
margin_right = 80.1041
|
||||||
|
margin_bottom = 227.182
|
||||||
|
texture = ExtResource( 2 )
|
||||||
|
expand = true
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="screeninfo" type="Label" parent="."]
|
||||||
|
margin_right = 108.0
|
||||||
|
margin_bottom = 15.0
|
||||||
|
rect_scale = Vector2( 2, 2 )
|
||||||
|
text = "Pos:, Chunk ID:, Pointing at:"
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|