Skip to content

Conversation

GCodergr
Copy link
Contributor

@GCodergr GCodergr commented Sep 7, 2025

Added core_3d_camera_fps.odin example which is based on raylib core_3d_camera_fps.c.
The original c example is playable here .

Checklist before submitting:

  • This example has been added to .github/workflows/check.yml (for automatic testing)
  • This example compiles cleanly with flags -vet -strict-style -vet-tabs -disallow-do -warnings-as-errors
  • This example follows the core naming convention: https://github.com/odin-lang/Odin/wiki/Naming-Convention (exception can be made for ports of examples that need to match 1:1 to the original source).
  • By submitting, I understand that this example is made available under these licenses: Public Domain and Odin's BSD-3 license. Only for third-party dependencies are other licenses allowed.

Copy link
Collaborator

@karl-zylinski karl-zylinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi. Thanks for the PR.

There are a bunch of unnecessary type specifications that I think came along from the C code. Such as this:
hvelLength: f32 = rl.Vector3Length(hvel)

Just use hvelLength := rl.Vector3Length(hvel)

Also, there is some weird "type double dipping" happening, such as this:
desiredDir: rl.Vector3 = rl.Vector3 {

Just do
desiredDir := rl.Vector3 {

I've only given a comment once for a specific issue, but most of them happen multiple times, so please look through the file.

Also, I've set up a style guide for the examples repository. Future PRs will have it linked in the template: https://github.com/odin-lang/examples/wiki/Naming-and-style-convention

}
}

TOWER_SIZE: rl.Vector3 : rl.Vector3{16.0, 32.0, 16.0}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TOWER_SIZE :: rl.Vector3{16.0, 32.0, 16.0}

}
}

delta: f32 = rl.GetFrameTime()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use type inference delta := rl.GetFrameTime()

body.velocity.y -= GRAVITY * delta
}

if (body.isGrounded && jumpPressed) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra parens

// Draw game level
draw_level :: proc() {
FLOOR_EXTENT: int : 25
TILE_SIZE: f32 : 5.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just do TILE_SIZE :: 5. It'll implicitly cast correctly when you use it.

lookRotation.x -= mouseDelta.x * sensitivity.x
lookRotation.y += mouseDelta.y * sensitivity.y

sideway := i8(i8(rl.IsKeyDown(.D)) - i8(rl.IsKeyDown(.A)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both are i8. The outer cast does nothing.

@GCodergr
Copy link
Contributor Author

GCodergr commented Oct 3, 2025

Hi. Thanks for the PR.

There are a bunch of unnecessary type specifications that I think came along from the C code. Such as this: hvelLength: f32 = rl.Vector3Length(hvel)

Just use hvelLength := rl.Vector3Length(hvel)

Also, there is some weird "type double dipping" happening, such as this: desiredDir: rl.Vector3 = rl.Vector3 {

Just do desiredDir := rl.Vector3 {

I've only given a comment once for a specific issue, but most of them happen multiple times, so please look through the file.

Also, I've set up a style guide for the examples repository. Future PRs will have it linked in the template: https://github.com/odin-lang/examples/wiki/Naming-and-style-convention

Once again, thank you Karl for all the suggestions! ❤️

The style guide is really helpful, especially for someone who writes code in multiple languages.

For the Raylib examples, I originally aimed for the structure to be close to the original C examples (one-to-one), but I agree it’s more important for the Odin examples to follow the recommended naming conventions and structure.

I’ll probably have some free time tomorrow to update the PR.

Much appreciated! 🙏

@GCodergr
Copy link
Contributor Author

GCodergr commented Oct 4, 2025

Updated the code based on the feedback and the naming and style conventions guide.

Used type inference where appropriate and explicitly assigned types in the remaining cases to avoid unnecessary casting.

Please let me know if there are any further changes needed.

Thank you Karl!

Copy link
Collaborator

@karl-zylinski karl-zylinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes. I put in a few more comments.

fovy = 60.0,
projection = .PERSPECTIVE,
position = rl.Vector3 {
player.position.x,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird indent. Should probably be

position = player.position + {0, BOTTOM_HEIGHT + headLerp, 0}


delta := rl.GetFrameTime()
headLerp = rl.Lerp(headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0 * delta)
camera.position = rl.Vector3 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

camera.position = player.position + {0, BOTTOM_HEIGHT + headLerp, 0}

// Module Functions Definition
//----------------------------------------------------------------------------------
// Update body considering current world state
update_body :: proc(body: ^Body,rot: f32, side: i8, forward: i8, jumpPressed: bool, crouchHold: bool) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Body,rot missing space

body.velocity.x = hvel.x
body.velocity.z = hvel.z

body.position.x += body.velocity.x * delta
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

body.position += body.velocity * delta


// Update camera for FPS behaviour
update_camera_fps :: proc(camera: ^rl.Camera) {
up :: rl.Vector3{0.0, 1.0, 0.0}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is a port so he camelCase for variables is OK, since the original does that. But all your other constants use SCREAMING_SNAKE_CASE. So this should either be a variable or be named UP

// Clamp view up
maxAngleUp := rl.Vector3Angle(up, yaw)
maxAngleUp -= 0.001 // Avoid numerical errors
if (-(lookRotation.y) > maxAngleUp) {lookRotation.y = -maxAngleUp}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you do a single line. A few lines below you split it into several lines. Also this has unneeded parens on the condition.

draw_level :: proc() {
FLOOR_EXTENT :: 25
TILE_SIZE :: 5.0
TILE_COLOR_1 := rl.Color{150, 200, 200, 255}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a constant, yet it has constant naming

TILE_COLOR_1 := rl.Color{150, 200, 200, 255}

// Floor tiles
for y: int = -FLOOR_EXTENT; y < FLOOR_EXTENT; y += 1 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could do

	for y in -FLOOR_EXTENT..<FLOOR_EXTENT {
		for x in -FLOOR_EXTENT..<FLOOR_EXTENT {

I understand this is a port. But anyways, if you feel like you prefer it, then change it. Always nice to show odin features etc.

rl.DrawCubeWiresV(towerPos, TOWER_SIZE, rl.DARKBLUE)

// Red sun
rl.DrawSphere(rl.Vector3{300.0, 300.0, 0.0}, 100, rl.Color{255, 0, 0, 255})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop the rl.Vector3 and rl.Color: Just write

`rl.DrawSphere({300.0, 300.0, 0.0}, 100, {255, 0, 0, 255})

rl.DrawText("Camera controls:", 15, 15, 10, rl.BLACK)
rl.DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, rl.BLACK)
rl.DrawText("- Look around: arrow keys or mouse", 15, 45, 10, rl.BLACK)
rl.DrawText(rl.TextFormat("- Velocity Len: (%06.3f)", rl.Vector2Length(rl.Vector2{player.velocity.x, player.velocity.z})), 15, 60, 10, rl.BLACK)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rl.Vector2Length(player.velocity.xz)

sensitivity := rl.Vector2{0.001, 0.001}

player: Body
lookRotation := rl.Vector2{0.0, 0.0}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lookRotation: rl.Vector2


player: Body
lookRotation := rl.Vector2{0.0, 0.0}
headTimer: f32 = 0.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

headTimer: f32 etc etc on these lines below

@GCodergr
Copy link
Contributor Author

GCodergr commented Oct 6, 2025

Thanks again for the comments!

I’ll try to find some time in the next few days to make the fixes.

The code was originally ported from the C example, so some C-style conventions slipped through.

It’s a good practice to replace those with more Odin-oriented features, especially in a public repository.

Appreciate the feedback, take care!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants