diff --git a/lib/objects/player.rb b/lib/objects/player.rb index 945adc6..b39b818 100644 --- a/lib/objects/player.rb +++ b/lib/objects/player.rb @@ -5,18 +5,23 @@ class IMICFPS attr_accessor :speed attr_reader :name, :bound_model, :first_person_view + def initialize(x: 0, y: 0, z: 0, bound_model: nil, scale: MODEL_METER_SCALE, backface_culling: true, auto_manage: true, terrain: nil) + @terrain = terrain + super(x: x, y: y, z: z, bound_model: model, scale: scale, backface_culling: backface_culling, auto_manage: auto_manage) + end def setup bind_model(ModelLoader.new(type: :obj, file_path: "objects/biped.obj", game_object: self)) - - @speed = 0.05 + @speed = 2.5 # meter's per second + @running_speed = 6.8 @old_speed = @speed + @mass = 72 # kg + @y_velocity = 0 + @floor = 0 @first_person_view = true @devisor = 500.0 @name_image = Gosu::Image.from_text("#{Etc.getlogin}", 100, font: "Consolas", align: :center) # @name_image.save("temp.png") - p @name_image.width/@devisor - p @name_image.height/@devisor @name_tex = @name_image.gl_tex_info array_of_pixels = @name_image.to_blob @@ -87,11 +92,13 @@ class IMICFPS def update super + @floor = @terrain.height_at(self) + relative_speed = @speed if button_down?(Gosu::KbLeftControl) - relative_speed = (@speed*10.0)*(delta_time/60.0) + relative_speed = (@running_speed)*(delta_time) else - relative_speed = @speed*(delta_time/60.0) + relative_speed = @speed*(delta_time) end relative_y_rotation = @y_rotation*-1 @@ -120,10 +127,30 @@ class IMICFPS @y_rotation-=relative_speed*100 end - @y-=relative_speed if button_down?(Gosu::KbC) || button_down?(Gosu::KbLeftShift) unless @y <= 0 - @y+=relative_speed if button_down?(Gosu::KbSpace) + if @_time_in_air + air_time = ((Gosu.milliseconds-@_time_in_air)/1000.0) + @y_velocity-=(IMICFPS::GRAVITY*air_time)*delta_time + end - @y = 0 if @y < 0 + if button_down?(Gosu::KbSpace) && !@jumping + @jumping = true + @_time_in_air = Gosu.milliseconds + else + if @jumping + if @y <= @floor + @falling = false; @jumping = false; @y_velocity = 0 + end + end + end + if @jumping && !@falling + if button_down?(Gosu::KbSpace) + @y_velocity+=(2*5)*delta_time + @falling = true if @y_velocity >= 2 + end + end + @y+=@y_velocity*delta_time + + @y = @floor if @y < @floor # distance = 2.0 # x_offset = distance * Math.cos(@bound_model.y_rotation) # z_offset = distance * Math.sin(@bound_model.y_rotation) diff --git a/lib/objects/terrain.rb b/lib/objects/terrain.rb index 1431149..f85495a 100644 --- a/lib/objects/terrain.rb +++ b/lib/objects/terrain.rb @@ -1,114 +1,167 @@ class IMICFPS - class Terrain - TILE_SIZE = 0.5 - include OpenGL - def initialize(size:, height: nil, width: nil, length: nil, heightmap: nil) - @size = size - @heightmap = heightmap - @map = [] + class Terrain < GameObject + def setup + bind_model(ModelLoader.new(type: :obj, file_path: "objects/randomish_terrain.obj", game_object: self)) + self.scale = 1 + @nearest_vertex_lookup = {} - @height = height ? height : 1 - @width = width ? width : @size - @length = length ? length : @size - - @vertices = [] - @normals = [] - @colors = [] - generate + generate_optimized_lists end - def generate - #@width.times do |x| - # @length.times do |z| - # # TRIANGLE STRIP (BROKEN) - # @map << Vertex.new((x+1)-@width.to_f/2, 0, z-@legth.to_f/2) - # @map << Vertex.new(x-@width.to_f/2, 0, (z+1)-@length.to_f/2) - # end - #end - @width.times do |x| - @length.times do |z| - # WORKING TRIANGLES - @map << Vertex.new(x-@width.to_f/2, @height, z-@length.to_f/2) - @map << Vertex.new((x+1)-@width.to_f/2, @height, z-@length.to_f/2) - @map << Vertex.new(x-@width.to_f/2, @height, (z+1)-@length.to_f/2) - # - @map << Vertex.new(x-@width.to_f/2, @height, (z+1)-@length.to_f/2) - @map << Vertex.new((x+1)-@width.to_f/2, @height, z-@length.to_f/2) - @map << Vertex.new((x+1)-@width.to_f/2, @height, (z+1)-@length.to_f/2) + def generate_optimized_lists + x_slot,y_slot = 0,0 + model.vertices.each do |vert| + x_slot = vert.x.round + y_slot = vert.y.round + + @nearest_vertex_lookup[x_slot] = {} unless @nearest_vertex_lookup[x_slot] + @nearest_vertex_lookup[x_slot][y_slot] = [] unless @nearest_vertex_lookup[x_slot][y_slot] + @nearest_vertex_lookup[x_slot][y_slot] << vert + end + end + + def height_at(vertex) + if vert = find_nearest_vertex(vertex) + return vert.y + else + -1 + end + end + + def find_nearest_vertex(vertex) + _canidate_for_floor = nil + smaller_list = [] + smaller_list << @nearest_vertex_lookup.dig(vertex.x.round-1, vertex.y.round-1) + smaller_list << @nearest_vertex_lookup.dig(vertex.x.round, vertex.y.round) + smaller_list << @nearest_vertex_lookup.dig(vertex.x.round+1, vertex.y.round+1) + smaller_list.flatten! + + smaller_list.each do |vert| + next if vert.nil? + if _canidate_for_floor + if Gosu.distance(vertex.x, vertex.z, vert.x, vert.z) < Gosu.distance(_canidate_for_floor.x, _canidate_for_floor.z, vert.x, vert.z) + _canidate_for_floor = vert + end end + + _canidate_for_floor = vert unless _canidate_for_floor end - @map.size.times do |i| - @vertices << @map[i].x - @vertices << @map[i].y - @vertices << @map[i].z - normal = Vertex.new(0,1,0) - @normals << normal.x - @normals << normal.y - @normals << normal.z - color = Color.new(0,rand(0.2..1.0),0) - @colors << color.red - @colors << color.green - @colors << color.blue - end - - @vertices_packed = @vertices.pack("f*") - @normals_packed = @normals.pack("f*") - @colors_packed = @colors.pack("f*") - end - - def draw - new_draw - # old_draw - end - - def old_draw - glEnable(GL_COLOR_MATERIAL) - - # glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) - glPointSize(5) - # glBegin(GL_LINES) - # glBegin(GL_POINTS) - glBegin(GL_TRIANGLES) - @map.each_with_index do |vertex, index| - glNormal3f(0,1,0) - glColor3f(0.0, 0.5, 0) if index.even? - glColor3f(0, 1.0, 0) if index.odd? - glVertex3f(vertex.x, vertex.y, vertex.z) - end - glEnd - - glDisable(GL_COLOR_MATERIAL) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) - end - - def new_draw - glEnable(GL_NORMALIZE) - glPushMatrix - - glEnable(GL_COLOR_MATERIAL) - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) - glShadeModel(GL_FLAT) - glEnableClientState(GL_VERTEX_ARRAY) - glEnableClientState(GL_NORMAL_ARRAY) - glEnableClientState(GL_COLOR_ARRAY) - - glVertexPointer(3, GL_FLOAT, 0, @vertices_packed) - glNormalPointer(GL_FLOAT, 0, @normals_packed) - glColorPointer(3, GL_FLOAT, 0, @colors_packed) - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) - glDrawArrays(GL_TRIANGLES, 0, @vertices.size/3) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) - - # glDrawArrays(GL_TRIANGLE_STRIP, 0, @vertices.size/3) - $window.number_of_faces+=@vertices.size/3 - - glDisableClientState(GL_VERTEX_ARRAY) - glDisableClientState(GL_NORMAL_ARRAY) - glDisableClientState(GL_COLOR_ARRAY) - - glPopMatrix + return _canidate_for_floor end end end +# class IMICFPS +# class Terrain +# TILE_SIZE = 0.5 +# include OpenGL +# def initialize(size:, height: nil, width: nil, length: nil, heightmap: nil) +# @size = size +# @heightmap = heightmap +# @map = [] + +# @height = height ? height : 1 +# @width = width ? width : @size +# @length = length ? length : @size + +# @vertices = [] +# @normals = [] +# @colors = [] +# generate +# end + +# def generate +# #@width.times do |x| +# # @length.times do |z| +# # # TRIANGLE STRIP (BROKEN) +# # @map << Vertex.new((x+1)-@width.to_f/2, 0, z-@legth.to_f/2) +# # @map << Vertex.new(x-@width.to_f/2, 0, (z+1)-@length.to_f/2) +# # end +# #end +# @width.times do |x| +# @length.times do |z| +# # WORKING TRIANGLES +# @map << Vertex.new(x-@width.to_f/2, @height, z-@length.to_f/2) +# @map << Vertex.new((x+1)-@width.to_f/2, @height, z-@length.to_f/2) +# @map << Vertex.new(x-@width.to_f/2, @height, (z+1)-@length.to_f/2) +# # +# @map << Vertex.new(x-@width.to_f/2, @height, (z+1)-@length.to_f/2) +# @map << Vertex.new((x+1)-@width.to_f/2, @height, z-@length.to_f/2) +# @map << Vertex.new((x+1)-@width.to_f/2, @height, (z+1)-@length.to_f/2) +# end +# end + +# @map.size.times do |i| +# @vertices << @map[i].x +# @vertices << @map[i].y +# @vertices << @map[i].z +# normal = Vertex.new(0,1,0) +# @normals << normal.x +# @normals << normal.y +# @normals << normal.z +# color = Color.new(rand(0.10..0.30),0,0) +# @colors << color.red +# @colors << color.green +# @colors << color.blue +# end + +# @vertices_packed = @vertices.pack("f*") +# @normals_packed = @normals.pack("f*") +# @colors_packed = @colors.pack("f*") +# end + +# def draw +# new_draw +# # old_draw +# end + +# def old_draw +# glEnable(GL_COLOR_MATERIAL) + +# # glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) +# glPointSize(5) +# # glBegin(GL_LINES) +# # glBegin(GL_POINTS) +# glBegin(GL_TRIANGLES) +# @map.each_with_index do |vertex, index| +# glNormal3f(0,1,0) +# glColor3f(0.0, 0.5, 0) if index.even? +# glColor3f(0, 1.0, 0) if index.odd? +# glVertex3f(vertex.x, vertex.y, vertex.z) +# end +# glEnd + +# glDisable(GL_COLOR_MATERIAL) +# glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) +# end + +# def new_draw +# glEnable(GL_NORMALIZE) +# glPushMatrix + +# glEnable(GL_COLOR_MATERIAL) +# glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) +# glShadeModel(GL_FLAT) +# glEnableClientState(GL_VERTEX_ARRAY) +# glEnableClientState(GL_NORMAL_ARRAY) +# glEnableClientState(GL_COLOR_ARRAY) + +# glVertexPointer(3, GL_FLOAT, 0, @vertices_packed) +# glNormalPointer(GL_FLOAT, 0, @normals_packed) +# glColorPointer(3, GL_FLOAT, 0, @colors_packed) + +# glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) +# glDrawArrays(GL_TRIANGLES, 0, @vertices.size/3) +# glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + +# # glDrawArrays(GL_TRIANGLE_STRIP, 0, @vertices.size/3) +# $window.number_of_faces+=@vertices.size/3 + +# glDisableClientState(GL_VERTEX_ARRAY) +# glDisableClientState(GL_NORMAL_ARRAY) +# glDisableClientState(GL_COLOR_ARRAY) + +# glPopMatrix +# end +# end +# end diff --git a/lib/wavefront/model.rb b/lib/wavefront/model.rb index e01ae68..857a458 100644 --- a/lib/wavefront/model.rb +++ b/lib/wavefront/model.rb @@ -10,7 +10,7 @@ class IMICFPS include Parser - attr_accessor :objects, :materials, :vertexes, :texures, :normals, :faces + attr_accessor :objects, :materials, :vertices, :texures, :normals, :faces attr_accessor :x, :y, :z, :scale attr_reader :bounding_box diff --git a/lib/window.rb b/lib/window.rb index 4d66c14..ad0ffb6 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -1,4 +1,5 @@ class IMICFPS + GRAVITY = 9.8 # m/s class Window < Gosu::Window include OpenGL include GLU @@ -29,9 +30,9 @@ class IMICFPS # Model.new(type: :obj, file_path: "objects/tree.obj", z: -5) # Model.new(type: :obj, file_path: "objects/tree.obj", x: -2, z: -6) # Model.new(type: :obj, file_path: "objects/sponza.obj", scale: 1, y: -0.2) - @terrain = Terrain.new(size: 170, height: 0) + @terrain = Terrain.new#(size: 170, height: 0) - @player = Player.new(x: 1, y: 0, z: -1) + @player = Player.new(x: 1, y: 0, z: -1, terrain: @terrain) @camera = Camera.new(x: 0, y: -2, z: 1) @camera.attach_to(@player) @@ -63,7 +64,6 @@ class IMICFPS @skydome.draw if @skydome.renderable glEnable(GL_DEPTH_TEST) - @terrain.draw if @terrain ObjectManager.objects.each do |object| object.draw if object.visible && object.renderable end @@ -97,17 +97,16 @@ Debug mode: #{$debug} eos @text.text = string - ObjectManager.objects.each do |object| - ObjectManager.objects.each do |b| - next if b == object - if object.intersect(object, b) - puts "#{object} is intersecting #{b}" - puts "#{object.x}, #{object.y} | #{b.x}, #{b.y}" - end - end - object.update - end - # ObjectManager.objects.each(&:update) + # ObjectManager.objects.each do |object| + # ObjectManager.objects.each do |b| + # next if b == object + # if object.intersect(object, b) + # # puts "#{object} is intersecting #{b}" + # end + # end + # object.update + # end + ObjectManager.objects.each(&:update) @skydome.update if @skydome.renderable @@ -143,7 +142,7 @@ eos end def delta_time - Gosu.milliseconds-@delta_time + (Gosu.milliseconds-@delta_time)/1000.0 end end end