summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/raylib/mrblib/touch_controls.rb
blob: c83dfbdd65d99f03f6402bc64ad1c9ac335c1747 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
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
module Jamstack
  class TouchControls
    attr_reader :joystick_vector

    def initialize(joystick_x: 100, joystick_y: nil, joystick_radius: 60)
      sw = Rl.screen_width
      sh = Rl.screen_height
      @jbx = joystick_x
      @jby = joystick_y || (sh - joystick_x)
      @jbr = joystick_radius
      @jknob_x = 0
      @jknob_y = 0
      @jvec = Rl::Vector2.new(0, 0)
      @jactive = false
      @jtouch_id = -1
      @buttons = []
    end

    def add_button(name, x:, y:, radius: 40, label: nil)
      @buttons << {
        name: name, x: x, y: y, r: radius,
        label: label || name.to_s.upcase,
        touch_id: -1, held: false, prev: false
      }
      self
    end

    def update
      count = Rl.get_touch_point_count
      ids = []
      count.times { |i| ids << [Rl.get_touch_point_id(i), Rl.get_touch_position(i)] }

      update_joystick(ids)
      update_buttons(ids)
    end

    def joystick
      @jvec
    end

    def button_down?(name)
      b = find_button(name)
      b && b[:held]
    end

    def button_pressed?(name)
      b = find_button(name)
      b && b[:held] && !b[:prev]
    end

    def draw
      draw_joystick
      @buttons.each { |b| draw_button(b) }
    end

    private

    def update_joystick(touches)
      if @jactive
        match = touches.find { |id, _| id == @jtouch_id }
        if match
          _, pos = match
          dx = pos.x - @jbx
          dy = pos.y - @jby
          dist = Math.sqrt(dx * dx + dy * dy)
          if dist > @jbr
            dx = dx * @jbr / dist
            dy = dy * @jbr / dist
          end
          @jknob_x = dx
          @jknob_y = dy
          @jvec = Rl::Vector2.new(dx / @jbr, dy / @jbr)
        else
          reset_joystick
        end
      else
        match = touches.find { |_, pos| dist(pos.x, pos.y, @jbx, @jby) <= @jbr }
        if match
          @jactive = true
          @jtouch_id = match[0]
        end
      end
    end

    def reset_joystick
      @jactive = false
      @jtouch_id = -1
      @jknob_x = 0
      @jknob_y = 0
      @jvec = Rl::Vector2.new(0, 0)
    end

    def update_buttons(touches)
      @buttons.each do |b|
        b[:prev] = b[:held]
        if b[:touch_id] >= 0
          if touches.any? { |id, _| id == b[:touch_id] }
            b[:held] = true
          else
            b[:held] = false
            b[:touch_id] = -1
          end
        elsif !b[:held]
          match = touches.find { |_, pos| dist(pos.x, pos.y, b[:x], b[:y]) <= b[:r] }
          if match
            b[:touch_id] = match[0]
            b[:held] = true
          end
        end
      end
    end

    def find_button(name)
      @buttons.find { |b| b[:name] == name }
    end

    def dist(x1, y1, x2, y2)
      dx = x1 - x2; dy = y1 - y2
      Math.sqrt(dx * dx + dy * dy)
    end

    def draw_joystick
      c_base = Rl::Color.new(255, 255, 255, 40)
      c_ring = Rl::Color.new(255, 255, 255, 120)
      c_knob = Rl::Color.new(200, 210, 240, 180)
      Rl.draw_circle(@jbx, @jby, @jbr, c_base)
      Rl.draw_circle_lines(@jbx, @jby, @jbr, c_ring)
      Rl.draw_circle(@jbx + @jknob_x, @jby + @jknob_y, @jbr / 3, c_knob)
    end

    def draw_button(b)
      alpha = b[:held] ? 200 : 60
      fill = Rl::Color.new(150, 200, 255, alpha)
      ring = Rl::Color.new(255, 255, 255, 120)
      Rl.draw_circle(b[:x], b[:y], b[:r], fill)
      Rl.draw_circle_lines(b[:x], b[:y], b[:r], ring)
      Rl.draw_text(text: b[:label], x: b[:x] - 6, y: b[:y] - 8,
                   font_size: 16, color: Rl::Color.new(255, 255, 255, 200))
    end
  end
end