Class: Quake::Physics::Player

Inherits:
Object
  • Object
show all
Defined in:
lib/quake/physics/player.rb

Overview

Full Quake player physics: gravity, friction, acceleration, jumping, ground detection, stair stepping, and swimming.

Constant Summary collapse

GRAVITY =

Quake constants

800.0
FRICTION =

units/sec^2

4.0
STOP_SPEED =
100.0
MAX_SPEED =
320.0
ACCELERATE =
10.0
AIR_ACCELERATE =
0.7
JUMP_SPEED =
270.0
STEP_SIZE =
18.0
WATER_FRICTION =
1.0
WATER_ACCELERATE =
10.0
SENSITIVITY =

Camera

0.15
MAX_MOUSE_DELTA =
50
VIEW_HEIGHT =

eye offset from origin (origin is at player feet center)

22.0
MIN_GROUND_NORMAL_Z =

Ground: surface normal Z must be > 0.7 (roughly < 45 degrees from horizontal)

0.7

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(position:, yaw: 0.0) ⇒ Player

Returns a new instance of Player.



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/quake/physics/player.rb', line 31

def initialize(position:, yaw: 0.0)
  @position = position
  @velocity = Math::Vec3::ORIGIN
  @yaw = yaw
  @pitch = 0.0
  @on_ground = false
  @water_level = 0 # 0=dry, 1=feet, 2=waist, 3=head
  @jump_held = false
  @noclip = false
  @ignore_mouse = 2
end

Instance Attribute Details

#noclipObject

Returns the value of attribute noclip.



8
9
10
# File 'lib/quake/physics/player.rb', line 8

def noclip
  @noclip
end

#on_groundObject

Returns the value of attribute on_ground.



8
9
10
# File 'lib/quake/physics/player.rb', line 8

def on_ground
  @on_ground
end

#pitchObject (readonly)

Returns the value of attribute pitch.



9
10
11
# File 'lib/quake/physics/player.rb', line 9

def pitch
  @pitch
end

#positionObject

Returns the value of attribute position.



8
9
10
# File 'lib/quake/physics/player.rb', line 8

def position
  @position
end

#velocityObject

Returns the value of attribute velocity.



8
9
10
# File 'lib/quake/physics/player.rb', line 8

def velocity
  @velocity
end

#water_levelObject

Returns the value of attribute water_level.



8
9
10
# File 'lib/quake/physics/player.rb', line 8

def water_level
  @water_level
end

#yawObject (readonly)

Returns the value of attribute yaw.



9
10
11
# File 'lib/quake/physics/player.rb', line 9

def yaw
  @yaw
end

Instance Method Details

#eye_positionObject

Camera eye position (origin + view height)



44
45
46
# File 'lib/quake/physics/player.rb', line 44

def eye_position
  Math::Vec3.new(@position.x, @position.y, @position.z + VIEW_HEIGHT)
end

#forwardObject

Full forward including pitch (for camera)



113
114
115
116
117
118
# File 'lib/quake/physics/player.rb', line 113

def forward
  ry = deg2rad(@yaw)
  rp = deg2rad(@pitch)
  cp = ::Math.cos(rp)
  Math::Vec3.new(::Math.cos(ry) * cp, ::Math.sin(ry) * cp, -::Math.sin(rp))
end

#forward_flatObject

Forward direction (horizontal only, for movement)



102
103
104
105
# File 'lib/quake/physics/player.rb', line 102

def forward_flat
  ry = deg2rad(@yaw)
  Math::Vec3.new(::Math.cos(ry), ::Math.sin(ry), 0.0)
end

#rightObject



120
121
122
123
# File 'lib/quake/physics/player.rb', line 120

def right
  ry = deg2rad(@yaw - 90.0)
  Math::Vec3.new(::Math.cos(ry), ::Math.sin(ry), 0.0)
end

#right_flatObject



107
108
109
110
# File 'lib/quake/physics/player.rb', line 107

def right_flat
  ry = deg2rad(@yaw - 90.0)
  Math::Vec3.new(::Math.cos(ry), ::Math.sin(ry), 0.0)
end

#rotate(dx, dy) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/quake/physics/player.rb', line 48

def rotate(dx, dy)
  if @ignore_mouse > 0
    @ignore_mouse -= 1
    return
  end
  dx = dx.clamp(-MAX_MOUSE_DELTA, MAX_MOUSE_DELTA)
  dy = dy.clamp(-MAX_MOUSE_DELTA, MAX_MOUSE_DELTA)
  @yaw -= dx * SENSITIVITY
  @pitch += dy * SENSITIVITY
  @pitch = @pitch.clamp(-89.0, 89.0)
end

#update(dt, level, keys, brush_entities: nil) ⇒ Object



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
# File 'lib/quake/physics/player.rb', line 60

def update(dt, level, keys, brush_entities: nil)
  if @noclip
    noclip_move(dt, keys)
    return
  end

  @brush_entities = brush_entities
  categorize_position(level)

  # Calculate wish direction from input
  wish_dir, wish_speed = compute_wish_velocity(keys)

  if @water_level >= 2
    water_move(dt, wish_dir, wish_speed, keys, level)
  else
    # Apply gravity if not on ground and not in water
    unless @on_ground
      @velocity = Math::Vec3.new(@velocity.x, @velocity.y,
                                 @velocity.z - GRAVITY * dt)
    end

    # Handle jumping (SET vz, don't add - matches Quake's PM_AirMove)
    if @on_ground && keys[SDL::SCANCODE_SPACE] && !@jump_held
      @velocity = Math::Vec3.new(@velocity.x, @velocity.y, JUMP_SPEED)
      @on_ground = false
      @jump_held = true
    end
    @jump_held = false unless keys[SDL::SCANCODE_SPACE]

    if @on_ground
      apply_friction(dt, level)
      accelerate(wish_dir, wish_speed, ACCELERATE, dt)
    else
      air_accelerate(wish_dir, wish_speed, dt)
    end
  end

  # Move with collision
  walk_move(dt, level)
end