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|
|
||||
|
140
chunk.gd
Normal file
@ -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
|
7
chunk.tscn
Normal file
@ -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 )
|
125
core.gd
Normal file
@ -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
|
7
default_env.tres
Normal file
@ -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 )
|
19
main.tscn
Normal file
@ -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 )
|
72
mapgen.gd
Normal file
@ -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)
|
94
player.gd
Normal file
@ -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
|
27
player.tscn
Normal file
@ -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"]
|
84
project.godot
Normal file
@ -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"
|
BIN
res/crosshair.png
Normal file
After Width: | Height: | Size: 602 B |
BIN
res/dirt.png
Normal file
After Width: | Height: | Size: 862 B |
BIN
res/grass.png
Normal file
After Width: | Height: | Size: 676 B |
BIN
res/grass_dirt.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
res/stone.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
res/water.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
screenshot.PNG
Normal file
After Width: | Height: | Size: 185 KiB |
29
ui.gd
Normal file
@ -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)
|
30
ui.tscn
Normal file
@ -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
|
||||
}
|