Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust Integration with SKM #66

Closed
wants to merge 6 commits into from
Closed

Conversation

NoahJCross
Copy link

Description

Added Rust as a supported language within SKM's Foreign Function Interface (FFI) system. This update enables SKM to handle Rust FFI calls alongside the existing supported languages, allowing Rust programs to properly interface with SplashKit's core functionality.

Changes Made

  • Added Rust language handling to SKM's FFI system
  • Implemented necessary FFI adapters for Rust integration
  • Added Rust to SKM's supported languages list
  • Integrated Rust FFI calling conventions into existing SKM infrastructure

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

  • Completed testing of Rust FFI functionality

Testing Note

I’m building a test runner to make testing more accessible for other users. This will be provided in a future PR with the tests. In the meantime I’ll provide a tutorial on how you can run a rust program.

Why this manual setup is necessary:

The SplashKit installation scripts download from the GitHub source project regardless of running the installation script locally. This means the files must be manually copied to your SplashKit directory to use the Rust implementation. The following steps ensure proper setup of the Rust environment for SplashKit.

Setting Up a Rust Project with SplashKit SDK

Prerequisites

  • SplashKit SDK must be installed
  • Git installed

Step 1: Clone the Repository

git clone https://github.com/NoahJCross/skm
cd skm

Step 2: Install dos2unix

Choose the appropriate command for your system:

  • MSYS2/MINGW64:
    pacman -S --needed --disable-download-timeout dos2unix
  • macOS:
    brew install dos2unix
  • Linux (Ubuntu):
    sudo apt-get install dos2unix

Step 3: Create Directory Structure

mkdir -p ~/.splashkit/{rust/src,new/rust/files/src,fix/rust}

Step 4: Copy Files

Copy entire directories with -r:

cp -r rust/{build.rs,Cargo.toml} ~/.splashkit/rust/
cp -r rust/src/lib.rs ~/.splashkit/rust/src/
cp -r new/rust/files/Cargo.toml ~/.splashkit/new/rust/files/
cp -r new/rust/files/src/main.rs ~/.splashkit/new/rust/files/src/
cp -r new/rust/{skm_new_rust.sh,lang_details.sh} ~/.splashkit/new/rust/
cp -r fix/rust/skm_fix_rust.sh ~/.splashkit/fix/rust/
cp -r new/{help.sh,new.sh} ~/.splashkit/new/
cp skm ~/.splashkit/

Step 5: Convert Line Endings

dos2unix ~/.splashkit/new/rust/skm_new_rust.sh
dos2unix ~/.splashkit/new/rust/lang_details.sh
dos2unix ~/.splashkit/fix/rust/skm_fix_rust.sh
dos2unix ~/.splashkit/new/help.sh
dos2unix ~/.splashkit/new/new.sh
dos2unix ~/.splashkit/skm

Step 6: Set File Permissions

chmod 755 ~/.splashkit/new/rust/skm_new_rust.sh
chmod 755 ~/.splashkit/new/rust/lang_details.sh
chmod 755 ~/.splashkit/fix/rust/skm_fix_rust.sh
chmod 755 ~/.splashkit/new/help.sh
chmod 755 ~/.splashkit/new/new.sh
chmod 755 ~/.splashkit/skm

Step 7: Create and Run a Test Project

mkdir rust_test
cd rust_test
skm new rust

At this point, you can either create your own program or use the provided sample code. Copy the sample code into src/main.rs.

Step 8: Build and Run

cargo build && cargo run

This will compile and run your Rust SplashKit project. The sample code creates a simple coin collector game with player movement, coins to collect, and enemies to avoid.

use splashkit::*;

fn main() {
    open_window("Coin Collector".to_string(), 800, 600);
    
    let bmp = create_bitmap("player".to_string(), 32, 32);
    clear_bitmap(bmp, color_blue());
    setup_collision_mask(bmp);
    
    let mut player_x: f64 = 400.0;
    let mut player_y: f64 = 300.0;
    let player_speed: f64 = 4.0;
    let player_size: f64 = 30.0;
    
    let mut score = 0;
    let mut game_time: f64 = 0.0;
    let mut is_game_over = false;
    let mut immunity_time: f64 = 3.0;
    
    let mut coins = Vec::new();
    let mut enemies = Vec::new();
    
    for _ in 0..5 {
        coins.push((
            rnd_int(700) as f64,
            rnd_int(500) as f64
        ));
        
        enemies.push((
          Rectangle {
              x: rnd_int(700) as f64,
              y: rnd_int(500) as f64,
              width: player_size,
              height: player_size
          },
          (rnd_int(2) as f64 + 1.0) * 0.5  
      ));
    }
    
    while !window_close_requested_named("Coin Collector".to_string()) {
        process_events();
        
        if !is_game_over {
            if key_down(KeyCode::LeftKey) {
                player_x -= player_speed;
            }
            if key_down(KeyCode::RightKey) {
                player_x += player_speed;
            }
            if key_down(KeyCode::UpKey) {
                player_y -= player_speed;
            }
            if key_down(KeyCode::DownKey) {
                player_y += player_speed;
            }
            
            player_x = player_x.clamp(0.0, 800.0 - player_size);
            player_y = player_y.clamp(0.0, 600.0 - player_size);

            for (enemy_rect, speed) in enemies.iter_mut() {
              if enemy_rect.x < player_x { enemy_rect.x += *speed; }
              if enemy_rect.x > player_x { enemy_rect.x -= *speed; }
              if enemy_rect.y < player_y { enemy_rect.y += *speed; }
              if enemy_rect.y > player_y { enemy_rect.y -= *speed; }
              
              if immunity_time <= 0.0 {
                  if bitmap_rectangle_collision(bmp, player_x, player_y, *enemy_rect) {
                      is_game_over = true;
                  }
              }
            }
            
            let mut new_coins = Vec::new();
            coins.retain(|(coin_x, coin_y)| {
                let coin_circle = Circle {
                    center: Point2D { x: *coin_x, y: *coin_y },
                    radius: 20.0
                };
                
                let collected = bitmap_circle_collision(bmp, player_x, player_y, coin_circle);
                if collected {
                    score += 10;
                    new_coins.push((rnd_int(700) as f64, rnd_int(500) as f64));
                }
                !collected
            });
            coins.extend(new_coins);
            
            game_time += 1.0 / 60.0;
            immunity_time -= 1.0 / 60.0;
        }
        
        clear_screen(color_black());
        
        for (coin_x, coin_y) in coins.iter() {
            fill_circle(color_yellow(), *coin_x, *coin_y, 10.0);
        }
        
        for (enemy_rect, _) in enemies.iter() {
          fill_rectangle_record(color_red(), *enemy_rect);
        }
        
        fill_rectangle(color_blue(), player_x, player_y, player_size, player_size);
        
        draw_text_no_font_no_size(format!("Score: {}", score).to_string(), color_white(), 10.0, 10.0);
        draw_text_no_font_no_size(format!("Time: {:.1}s", game_time).to_string(), color_white(), 10.0, 30.0);
        
        if is_game_over {
            draw_text_no_font_no_size("Game Over!".to_string(), color_red(), 350.0, 300.0);
            draw_text_no_font_no_size("Close window to exit".to_string(), color_white(), 320.0, 330.0);
        }
        
        refresh_screen_with_target_fps(60);
    }
}

Checklist

  • Code follows the style guidelines of this project
  • Self-review completed
  • Changes generate no new warnings
  • Testing completed and verified working
  • Provided example program

@NoahJCross NoahJCross marked this pull request as draft January 6, 2025 12:12
@NoahJCross NoahJCross closed this Jan 6, 2025
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