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
STOP_EPSILON =

units/sec^2

0.1
FRICTION =
4.0
EDGE_FRICTION =
2.0
STOP_SPEED =
100.0
MAX_SPEED =
320.0
MAX_VELOCITY =
2000.0
FORWARD_SPEED =
200.0
BACK_SPEED =
200.0
SIDE_SPEED =
350.0
UP_SPEED =
200.0
ACCELERATE =
10.0
AIR_ACCELERATE =
10.0
JUMP_SPEED =
270.0
STEP_SIZE =
18.0
WATER_FRICTION =
4.0
WATER_ACCELERATE =
10.0
UNSTICK_DISTANCE =
2.0
MIN_UNSTICK_PROGRESS =
4.0
UNSTICK_DIRECTIONS =
[
  Math::Vec3.new(UNSTICK_DISTANCE, 0.0, 0.0),
  Math::Vec3.new(0.0, UNSTICK_DISTANCE, 0.0),
  Math::Vec3.new(-UNSTICK_DISTANCE, 0.0, 0.0),
  Math::Vec3.new(0.0, -UNSTICK_DISTANCE, 0.0),
  Math::Vec3.new(UNSTICK_DISTANCE, UNSTICK_DISTANCE, 0.0),
  Math::Vec3.new(-UNSTICK_DISTANCE, UNSTICK_DISTANCE, 0.0),
  Math::Vec3.new(UNSTICK_DISTANCE, -UNSTICK_DISTANCE, 0.0),
  Math::Vec3.new(-UNSTICK_DISTANCE, -UNSTICK_DISTANCE, 0.0)
].freeze
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
MAX_CLIP_PLANES =

SV_FlyMove (sv_phys.c)

5
CLIP_FLOOR =
1 << 0
CLIP_WALL =
1 << 1
CLIP_STOP =
1 << 2
WATER_JUMP_SPEED =

CheckWaterJump (client.qc)

225.0
WATER_JUMP_TIME =

teleport_time safety net: time + 2

2.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Player.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/quake/physics/player.rb', line 62

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
  @water_type = CONTENTS_EMPTY
  @jump_held = false
  @noclip = false
  @gravity = GRAVITY
  @ignore_mouse = 2
  @water_jump = false
  @water_jump_movedir = Math::Vec3::ORIGIN
  @water_jump_time = 0.0
end

Instance Attribute Details

#gravityObject

Returns the value of attribute gravity.



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

def gravity
  @gravity
end

#jump_heldObject (readonly)

Returns the value of attribute jump_held.



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

def jump_held
  @jump_held
end

#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.



11
12
13
# File 'lib/quake/physics/player.rb', line 11

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_jumpObject

Returns the value of attribute water_jump.



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

def water_jump
  @water_jump
end

#water_jump_movedirObject

Returns the value of attribute water_jump_movedir.



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

def water_jump_movedir
  @water_jump_movedir
end

#water_jump_timeObject

Returns the value of attribute water_jump_time.



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

def water_jump_time
  @water_jump_time
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

#water_typeObject

Returns the value of attribute water_type.



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

def water_type
  @water_type
end

#yawObject (readonly)

Returns the value of attribute yaw.



11
12
13
# File 'lib/quake/physics/player.rb', line 11

def yaw
  @yaw
end

Instance Method Details

#eye_positionObject

Camera eye position (origin + view height)



80
81
82
# File 'lib/quake/physics/player.rb', line 80

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

#forwardObject

Full forward including pitch (for camera)



159
160
161
162
163
164
# File 'lib/quake/physics/player.rb', line 159

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)



148
149
150
151
# File 'lib/quake/physics/player.rb', line 148

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

#rightObject



166
167
168
169
# File 'lib/quake/physics/player.rb', line 166

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

#right_flatObject



153
154
155
156
# File 'lib/quake/physics/player.rb', line 153

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

#rotate(dx, dy) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/quake/physics/player.rb', line 84

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

#upObject



171
172
173
174
175
176
177
178
179
# File 'lib/quake/physics/player.rb', line 171

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

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



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/quake/physics/player.rb', line 96

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

  @brush_entities = brush_entities
  check_velocity
  categorize_position(level)

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

  # QuakeC PlayerPreThink: probe for a jump-out-of-water while swimming
  check_water_jump(level) if @water_level == 2 && !@water_jump

  if @water_jump
    # SV_ClientThink short-circuits friction/accel while FL_WATERJUMP
    # is set (sv_user.c:357-360); SV_Physics_Client skips gravity.
    @water_jump_time -= dt
    water_jump_move
  elsif @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 (QuakeC PlayerJump: velocity_z = velocity_z + 270)
    if @on_ground && keys[SDL::SCANCODE_SPACE] && !@jump_held
      @velocity = Math::Vec3.new(@velocity.x, @velocity.y,
                                 @velocity.z + 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