mirror of
https://github.com/cyberarm/i-mic-fps.git
synced 2025-12-13 06:42:35 +00:00
Added more hud widgets for showing squadmates and crosshair, added crosshair image and source svg, hackish fix to make renderer resize on windows size change, added CameraController camera control is back in 😂
This commit is contained in:
90
lib/camera_controller.rb
Normal file
90
lib/camera_controller.rb
Normal file
@@ -0,0 +1,90 @@
|
||||
class IMICFPS
|
||||
class CameraController
|
||||
include CommonMethods
|
||||
|
||||
def initialize(mode: :fpv, camera:, entity:)
|
||||
# :fpv - First Person View
|
||||
# :tpv - Third Person View
|
||||
@mode = mode
|
||||
@camera = camera
|
||||
@entity = entity
|
||||
|
||||
@distance = 4
|
||||
@origin_distance = @distance
|
||||
@constant_pitch = 0
|
||||
|
||||
window.mouse_x, window.mouse_y = window.width / 2, window.height / 2
|
||||
|
||||
@true_mouse = Point.new(window.width / 2, window.height / 2)
|
||||
@mouse_sensitivity = 20.0 # Less is faster, more is slower
|
||||
@mouse_captured = true
|
||||
@mouse_checked = 0
|
||||
end
|
||||
|
||||
def distance_from_object
|
||||
@distance
|
||||
end
|
||||
|
||||
def horizontal_distance_from_object
|
||||
distance_from_object * Math.cos(@constant_pitch)
|
||||
end
|
||||
|
||||
def vertical_distance_from_object
|
||||
distance_from_object * Math.sin(@constant_pitch)
|
||||
end
|
||||
|
||||
def position_camera
|
||||
if defined?(@entity.first_person_view)
|
||||
if @entity.first_person_view
|
||||
@distance = 0
|
||||
else
|
||||
@distance = @origin_distance
|
||||
end
|
||||
end
|
||||
|
||||
x_offset = horizontal_distance_from_object * Math.sin(@entity.orientation.y.degrees_to_radians)
|
||||
z_offset = horizontal_distance_from_object * Math.cos(@entity.orientation.y.degrees_to_radians)
|
||||
|
||||
eye_height = @entity.bounding_box.max.y
|
||||
|
||||
@camera.position.x = @entity.position.x - x_offset
|
||||
@camera.position.y = @entity.position.y + eye_height
|
||||
@camera.position.z = @entity.position.z - z_offset
|
||||
|
||||
@camera.orientation.y = 180 - @entity.orientation.y
|
||||
end
|
||||
|
||||
def update
|
||||
position_camera
|
||||
|
||||
if @mouse_captured
|
||||
delta = Float(@true_mouse.x - self.mouse_x) / (@mouse_sensitivity * @camera.field_of_view) * 70
|
||||
@camera.orientation.y -= delta
|
||||
@camera.orientation.y %= 360.0
|
||||
|
||||
@camera.orientation.x -= Float(@true_mouse.y - window.mouse_y) / (@mouse_sensitivity * @camera.field_of_view) * 70
|
||||
@camera.orientation.x = @camera.orientation.x.clamp(-90.0, 90.0)
|
||||
|
||||
@entity.orientation.y += delta
|
||||
@entity.orientation.y %= 360.0
|
||||
|
||||
window.mouse_x = window.width / 2 if window.mouse_x <= 1 || window.mouse_x >= window.width-1
|
||||
window.mouse_y = window.height / 2 if window.mouse_y <= 1 || window.mouse_y >= window.height-1
|
||||
@true_mouse.x, @true_mouse.y = window.mouse_x, window.mouse_y
|
||||
end
|
||||
end
|
||||
|
||||
def button_down(id)
|
||||
case id
|
||||
when Gosu::KB_LEFT_ALT, Gosu::KB_RIGHT_ALT
|
||||
@mouse_captured = false
|
||||
window.needs_cursor = true
|
||||
when Gosu::MS_LEFT, Gosu::MS_MIDDLE, Gosu::MS_RIGHT
|
||||
@mouse_captured = true
|
||||
window.needs_cursor = false
|
||||
end
|
||||
end
|
||||
|
||||
def button_up(id); end
|
||||
end
|
||||
end
|
||||
@@ -6,6 +6,8 @@ class IMICFPS
|
||||
@health = HealthWidget.new({ player: player })
|
||||
@chat_history = ChatHistoryWidget.new({ player: player })
|
||||
@score_board = ScoreBoardWidget.new({ player: player })
|
||||
@squad = SquadWidget.new( { player: player } )
|
||||
@crosshair = CrosshairWidget.new( { player: player } )
|
||||
|
||||
@hud_elements = [
|
||||
@ammo,
|
||||
@@ -13,6 +15,9 @@ class IMICFPS
|
||||
@health,
|
||||
@chat_history,
|
||||
@score_board,
|
||||
@squad,
|
||||
|
||||
@crosshair,
|
||||
]
|
||||
end
|
||||
|
||||
@@ -24,4 +29,4 @@ class IMICFPS
|
||||
@hud_elements.each(&:update)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
36
lib/hud/widgets/crosshair.rb
Normal file
36
lib/hud/widgets/crosshair.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
class IMICFPS
|
||||
class HUD
|
||||
class CrosshairWidget < HUD::Widget
|
||||
def setup
|
||||
@scale = 0.75
|
||||
@color = Gosu::Color.new(0x44ffffff)
|
||||
|
||||
@image = Gosu::Image.new("#{GAME_ROOT_PATH}/static/crosshairs/crosshair.png")
|
||||
|
||||
@last_changed_time = Gosu.milliseconds
|
||||
@change_interval = 1_500
|
||||
|
||||
@colors = [0xffffffff, 0xaaffffff, 0x88ffffff, 0x22ffffff]
|
||||
end
|
||||
|
||||
def draw
|
||||
@image.draw(
|
||||
window.width / 2 - (@image.width * @scale) / 2,
|
||||
window.height / 2 - (@image.height * @scale) / 2,
|
||||
46,
|
||||
@scale,
|
||||
@scale,
|
||||
@color
|
||||
)
|
||||
end
|
||||
|
||||
def update
|
||||
if Gosu.milliseconds - @last_changed_time >= @change_interval
|
||||
@last_changed_time = Gosu.milliseconds
|
||||
|
||||
@color = @colors.sample
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,8 @@ class IMICFPS
|
||||
@radar_color = Gosu::Color.new(0x88212121)
|
||||
|
||||
@text = Text.new("RADAR", size: 18, mode: :add, font: MONOSPACE_FONT)
|
||||
@image = Gosu::Image.new("#{CYBERARM_ENGINE_ROOT_PATH}/assets/textures/default.png", retro: true)
|
||||
@scale = (@size - @padding * 2.0) / @image.width
|
||||
end
|
||||
|
||||
def draw
|
||||
@@ -21,15 +23,17 @@ class IMICFPS
|
||||
@size - @padding * 2, @size - @padding * 2,
|
||||
@radar_color
|
||||
)
|
||||
|
||||
@image.draw(@margin + @padding, window.height - (@size + @margin) + @padding, 46, @scale, @scale, 0x88ffffff)
|
||||
|
||||
@text.draw
|
||||
end
|
||||
|
||||
def update
|
||||
@text.text = "RADAR: X #{@player.position.x.round(1)} Y #{@player.position.z.round(1)}"
|
||||
@text.text = "RADAR: X #{@player.position.x.round(1)} Y #{@player.position.y.round(1)} Z #{@player.position.z.round(1)}"
|
||||
@text.x = @margin + @size / 2 - @text.width / 2
|
||||
@text.y = window.height - (@margin + @size + @text.height)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
21
lib/hud/widgets/squad.rb
Normal file
21
lib/hud/widgets/squad.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
class IMICFPS
|
||||
class HUD
|
||||
class SquadWidget < HUD::Widget
|
||||
def setup
|
||||
@size = 288 # RADAR size
|
||||
@color = Gosu::Color.new(0x8800aa00)
|
||||
|
||||
@text = Text.new("MATE\nTinyTanker\nOther Player Dude\nHuman 0xdeadbeef", size: 18, mode: :add, font: MONOSPACE_FONT, color: @color)
|
||||
end
|
||||
|
||||
def draw
|
||||
@text.draw
|
||||
end
|
||||
|
||||
def update
|
||||
@text.x = @margin + @size + @padding
|
||||
@text.y = window.height - (@margin + @text.height)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,17 +8,15 @@ class IMICFPS
|
||||
|
||||
@player = @map.find_entity_by(name: "character")
|
||||
@camera = PerspectiveCamera.new( position: @player.position.clone, aspect_ratio: window.aspect_ratio )
|
||||
@camera_controller = CameraController.new(mode: :first_person, camera: @camera, entity: @player)
|
||||
@director = Networking::Director.new
|
||||
@director.load_map(map_parser: @options[:map_parser])
|
||||
|
||||
@connection = Networking::Connection.new(address: "localhost", port: Networking::DEFAULT_SERVER_PORT)
|
||||
@connection.connect
|
||||
|
||||
@crosshair = Crosshair.new
|
||||
@hud = HUD.new(@player)
|
||||
|
||||
@text = Text.new("Pending...", x: 10, y: 22, z: 1, size: 18, font: "DejaVu Sans", shadow_color: Gosu::Color::BLACK)
|
||||
|
||||
if ARGV.join.include?("--playdemo")
|
||||
@demo = Demo.new(camera: @camera, player: @player, demo: "./demo.dat", mode: :play) if File.exist?("./demo.dat")
|
||||
|
||||
@@ -30,9 +28,7 @@ class IMICFPS
|
||||
def draw
|
||||
@map.render(@camera)
|
||||
|
||||
@crosshair.draw
|
||||
@hud.draw
|
||||
@text.draw
|
||||
end
|
||||
|
||||
def update
|
||||
@@ -40,17 +36,12 @@ class IMICFPS
|
||||
|
||||
control_player
|
||||
@hud.update
|
||||
@camera_controller.update
|
||||
|
||||
@connection.update
|
||||
@director.tick(window.dt)
|
||||
@map.update
|
||||
|
||||
if window.config.get(:debug_options, :stats)
|
||||
@text.text = update_text
|
||||
else
|
||||
@text.text = ""
|
||||
end
|
||||
|
||||
@demo.update if @demo
|
||||
end
|
||||
|
||||
@@ -60,13 +51,6 @@ OpenGL Vendor: #{glGetString(GL_VENDOR)}
|
||||
OpenGL Renderer: #{glGetString(GL_RENDERER)}
|
||||
OpenGL Version: #{glGetString(GL_VERSION)}
|
||||
OpenGL Shader Language Version: #{glGetString(GL_SHADING_LANGUAGE_VERSION)}
|
||||
|
||||
Camera Pitch: #{@camera.orientation.x.round(2)} Yaw: #{@camera.orientation.y.round(2)} Roll #{@camera.orientation.z.round(2)}
|
||||
Camera X: #{@camera.position.x.round(2)} Y: #{@camera.position.y.round(2)} Z: #{@camera.position.z.round(2)}
|
||||
Camera Field Of View: #{@camera.field_of_view}
|
||||
Camera Mouse Sesitivity: nil
|
||||
|
||||
Player X: #{@player.position.x.round(2)} Y: #{@player.position.y.round(2)} Z: #{@player.position.z.round(2)}"
|
||||
eos
|
||||
end
|
||||
|
||||
@@ -88,6 +72,7 @@ eos
|
||||
return
|
||||
end
|
||||
@demo.button_down(id) if @demo
|
||||
@camera_controller.button_down(id)
|
||||
|
||||
InputMapper.keydown(id)
|
||||
Publisher.instance.publish(:button_down, nil, id)
|
||||
@@ -99,6 +84,7 @@ eos
|
||||
|
||||
def button_up(id)
|
||||
@demo.button_up(id) if @demo
|
||||
@camera_controller.button_up(id)
|
||||
|
||||
InputMapper.keyup(id)
|
||||
Publisher.instance.publish(:button_up, nil, id)
|
||||
|
||||
@@ -64,7 +64,7 @@ class IMICFPS
|
||||
|
||||
_canvas_size = Vector.new(self.width, self.height)
|
||||
if @canvas_size != _canvas_size
|
||||
@renderer.canvas_size_changed
|
||||
@renderer = Renderer.new#@renderer.canvas_size_changed
|
||||
@canvas_size = _canvas_size
|
||||
end
|
||||
end
|
||||
|
||||
BIN
static/crosshairs/crosshair.png
Normal file
BIN
static/crosshairs/crosshair.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
118
svg/crosshairs/crosshair.svg
Normal file
118
svg/crosshairs/crosshair.svg
Normal file
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
sodipodi:docname="crosshair.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
id="svg140"
|
||||
version="1.1"
|
||||
viewBox="0 0 33.866666 33.866668"
|
||||
height="128"
|
||||
width="128">
|
||||
<defs
|
||||
id="defs134" />
|
||||
<sodipodi:namedview
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1010"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:showpageshadow="false"
|
||||
units="px"
|
||||
showgrid="true"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:cy="67.12637"
|
||||
inkscape:cx="91.154586"
|
||||
inkscape:zoom="5.6"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base">
|
||||
<inkscape:grid
|
||||
empspacing="8"
|
||||
id="grid162"
|
||||
type="xygrid" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata137">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<path
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
d="M 16.933332,8.46667 A 8.4666841,8.4666841 0 0 0 8.466665,16.93333 8.4666841,8.4666841 0 0 0 16.933332,25.4 8.4666841,8.4666841 0 0 0 25.399998,16.93333 8.4666841,8.4666841 0 0 0 16.933332,8.46667 Z m -0.03824,0.52916 a 7.9375172,7.9375172 0 0 1 0.03824,0 7.9375172,7.9375172 0 0 1 7.9375,7.9375 7.9375172,7.9375172 0 0 1 -7.9375,7.9375 7.9375172,7.9375172 0 0 1 -7.9375,-7.9375 7.9375172,7.9375172 0 0 1 7.89926,-7.9375 z"
|
||||
style="fill:#ffffff;stroke:none;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
|
||||
id="path1466" />
|
||||
<circle
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
r="0.52916473"
|
||||
cy="16.933329"
|
||||
cx="16.933331"
|
||||
id="path1475"
|
||||
style="fill:#ffffff;stroke:none;stroke-width:0.264583;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path1479"
|
||||
d="M 7.937498,16.93333 H 2.645828"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 31.220839,16.93333 H 25.929168"
|
||||
id="path1490"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 10.572318,10.57231 6.830539,6.83054"
|
||||
id="path1492"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path1494"
|
||||
d="m 27.036128,27.03612 -3.74178,-3.74177"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path1496"
|
||||
d="m 16.933338,7.93749 -10e-6,-5.29167"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 16.933338,31.22084 -10e-6,-5.29167"
|
||||
id="path1498"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
Reference in New Issue
Block a user