input virtual controls
There is no browser build of this example yet.
Is it the same as C?
- Desktop:verified The Zig version renders a final frame that is byte-identical to the C example.
- Browser:not checked yet The browser comparison does not cover this example yet.
//! raylib [core] example - input virtual controls
//!
//! Zig-API translation of examples/core/core_input_virtual_controls.c (raylib 6.2).
//! Example contributed by GreenSnakeLinux (@GreenSnakeLinux),
//! reviewed by Ramon Santamaria (@raysan5)
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2024-2025 GreenSnakeLinux (@GreenSnakeLinux) and Ramon Santamaria (@raysan5)
const rl = @import("raylib");
const PadButton = enum { up, left, right, down };
pub fn main() void {
// Initialization
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [core] example - input virtual controls");
defer rl.closeWindow(); // Close window and OpenGL context
const pad_position: rl.Vector2 = .{ .x = 100, .y = 350 };
const button_radius: f32 = 30;
const button_positions = [_]rl.Vector2{
.{ .x = pad_position.x, .y = pad_position.y - button_radius * 1.5 }, // Up
.{ .x = pad_position.x - button_radius * 1.5, .y = pad_position.y }, // Left
.{ .x = pad_position.x + button_radius * 1.5, .y = pad_position.y }, // Right
.{ .x = pad_position.x, .y = pad_position.y + button_radius * 1.5 }, // Down
};
const up = button_positions[0];
const left = button_positions[1];
const right = button_positions[2];
const down = button_positions[3];
const arrow_tris = [_][3]rl.Vector2{
// Up
.{
.{ .x = up.x, .y = up.y - 12 },
.{ .x = up.x - 9, .y = up.y + 9 },
.{ .x = up.x + 9, .y = up.y + 9 },
},
// Left
.{
.{ .x = left.x + 9, .y = left.y - 9 },
.{ .x = left.x - 12, .y = left.y },
.{ .x = left.x + 9, .y = left.y + 9 },
},
// Right
.{
.{ .x = right.x + 12, .y = right.y },
.{ .x = right.x - 9, .y = right.y - 9 },
.{ .x = right.x - 9, .y = right.y + 9 },
},
// Down
.{
.{ .x = down.x - 9, .y = down.y - 9 },
.{ .x = down.x, .y = down.y + 12 },
.{ .x = down.x + 9, .y = down.y - 9 },
},
};
const button_label_colors = [_]rl.Color{
.yellow, // Up
.blue, // Left
.red, // Right
.green, // Down
};
var player_position: rl.Vector2 = .{ .x = screen_width / 2.0, .y = screen_height / 2.0 };
const player_speed: f32 = 75;
rl.setTargetFPS(60);
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
const touching = rl.getTouchPointCount() > 0;
// Use touch position, or mouse position
const input_position = if (touching) rl.getTouchPosition(0) else rl.getMousePosition();
// Make sure user is pressing left mouse button if they're from desktop
var pressed_button: ?PadButton = null;
if (touching or rl.isMouseButtonDown(.left)) {
// Find nearest D-Pad button to the input position
for (button_positions, 0..) |position, i| {
const dist_x = @abs(position.x - input_position.x);
const dist_y = @abs(position.y - input_position.y);
if (dist_x + dist_y < button_radius) {
pressed_button = @fromBackingInt(@intCast(i));
break;
}
}
}
// Move player according to pressed button
if (pressed_button) |button| switch (button) {
.up => player_position.y -= player_speed * rl.getFrameTime(),
.left => player_position.x -= player_speed * rl.getFrameTime(),
.right => player_position.x += player_speed * rl.getFrameTime(),
.down => player_position.y += player_speed * rl.getFrameTime(),
};
// Draw
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
// Draw world
rl.drawCircleV(player_position, 50, .maroon);
// Draw GUI
for (button_positions, arrow_tris, button_label_colors, 0..) |position, tri, label_color, i| {
const pressed = if (pressed_button) |button| @backingInt(button) == i else false;
rl.drawCircleV(position, button_radius, if (pressed) .dark_gray else .black);
rl.drawTriangle(tri[0], tri[1], tri[2], label_color);
}
rl.drawText("move the player with D-Pad buttons", 10, 10, 20, .dark_gray);
}
}/*******************************************************************************************
*
* raylib [core] example - input virtual controls
*
* Example complexity rating: [★★☆☆] 2/4
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
* Example contributed by GreenSnakeLinux (@GreenSnakeLinux),
* reviewed by Ramon Santamaria (@raysan5), oblerion (@oblerion) and danilwhale (@danilwhale)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2024-2025 GreenSnakeLinux (@GreenSnakeLinux) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include <math.h>
typedef enum {
BUTTON_NONE = -1,
BUTTON_UP,
BUTTON_LEFT,
BUTTON_RIGHT,
BUTTON_DOWN,
BUTTON_MAX
} PadButton;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");
Vector2 padPosition = { 100, 350 };
float buttonRadius = 30;
Vector2 buttonPositions[BUTTON_MAX] = {
{ padPosition.x,padPosition.y - buttonRadius*1.5f }, // Up
{ padPosition.x - buttonRadius*1.5f, padPosition.y }, // Left
{ padPosition.x + buttonRadius*1.5f, padPosition.y }, // Right
{ padPosition.x, padPosition.y + buttonRadius*1.5f } // Down
};
Vector2 arrowTris[4][3] = {
// Up
{
{ buttonPositions[0].x, buttonPositions[0].y - 12 },
{ buttonPositions[0].x - 9, buttonPositions[0].y + 9 },
{ buttonPositions[0].x + 9, buttonPositions[0].y + 9 }
},
// Left
{
{ buttonPositions[1].x + 9, buttonPositions[1].y - 9 },
{ buttonPositions[1].x - 12, buttonPositions[1].y },
{ buttonPositions[1].x + 9, buttonPositions[1].y + 9 }
},
// Right
{
{ buttonPositions[2].x + 12, buttonPositions[2].y },
{ buttonPositions[2].x - 9, buttonPositions[2].y - 9 },
{ buttonPositions[2].x - 9, buttonPositions[2].y + 9 }
},
// Down
{
{ buttonPositions[3].x - 9, buttonPositions[3].y - 9 },
{ buttonPositions[3].x, buttonPositions[3].y + 12 },
{ buttonPositions[3].x + 9, buttonPositions[3].y - 9 }
}
};
Color buttonLabelColors[BUTTON_MAX] = {
YELLOW, // Up
BLUE, // Left
RED, // Right
GREEN // Down
};
int pressedButton = BUTTON_NONE;
Vector2 inputPosition = { 0, 0 };
Vector2 playerPosition = { (float)screenWidth/2, (float)screenHeight/2 };
float playerSpeed = 75;
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//--------------------------------------------------------------------------
if ((GetTouchPointCount() > 0)) inputPosition = GetTouchPosition(0); // Use touch position
else inputPosition = GetMousePosition(); // Use mouse position
// Reset pressed button to none
pressedButton = BUTTON_NONE;
// Make sure user is pressing left mouse button if they're from desktop
if ((GetTouchPointCount() > 0) ||
((GetTouchPointCount() == 0) && IsMouseButtonDown(MOUSE_BUTTON_LEFT)))
{
// Find nearest D-Pad button to the input position
for (int i = 0; i < BUTTON_MAX; i++)
{
float distX = fabsf(buttonPositions[i].x - inputPosition.x);
float distY = fabsf(buttonPositions[i].y - inputPosition.y);
if ((distX + distY < buttonRadius))
{
pressedButton = i;
break;
}
}
}
// Move player according to pressed button
switch (pressedButton)
{
case BUTTON_UP: playerPosition.y -= playerSpeed*GetFrameTime(); break;
case BUTTON_LEFT: playerPosition.x -= playerSpeed*GetFrameTime(); break;
case BUTTON_RIGHT: playerPosition.x += playerSpeed*GetFrameTime(); break;
case BUTTON_DOWN: playerPosition.y += playerSpeed*GetFrameTime(); break;
default: break;
};
//--------------------------------------------------------------------------
// Draw
//--------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
// Draw world
DrawCircleV(playerPosition, 50, MAROON);
// Draw GUI
for (int i = 0; i < BUTTON_MAX; i++)
{
DrawCircleV(buttonPositions[i], buttonRadius, (i == pressedButton)? DARKGRAY : BLACK);
DrawTriangle(
arrowTris[i][0],
arrowTris[i][1],
arrowTris[i][2],
buttonLabelColors[i]
);
}
DrawText("move the player with D-Pad buttons", 10, 10, 20, DARKGRAY);
EndDrawing();
//--------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}From raylib 6.2. The original on GitHub.