You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust移植终端3D甜甜圈动画出现字符残留问题求助

Rust移植3D甜甜圈动画字符残留问题修复

问题根源

  1. char类型内存填充错误:Rust的char是4字节Unicode标量值,原代码用std::ptr::write_bytes仅填充每个char的首字节为空格(32u8),剩余3字节未清零,导致旧字符数据残留。
  2. 数组越界访问:输出循环中k < 1761会访问b[1760],超出数组(长度1760)的有效索引范围(0-1759)。
  3. 角度增量逻辑错误:每输出一个字符就递增旋转角度A和B,导致单帧内角度不断变化,动画异常。
  4. 不必要的unsafe操作:用unsafe方式重置数组容易出错,Rust提供了更安全的替代方案。

修正后的代码

use std::{io, thread, time};
use clearscreen;

fn main() {
    let stdout = io::stdout();
    let mut handle = stdout.lock();

    let mut A: f32 = 0.0;
    let mut B: f32 = 0.0;
    let mut z: [f32; 1760] = [0.0; 1760];
    // 用u8数组替代char数组,匹配原C代码的单字节字符逻辑
    let mut b: [u8; 1760] = [b' '; 1760];
    // 将字符集提到循环外,避免重复创建
    let chars = [b'.', b',', b'-', b'~', b':', b';', b'=', b'!', b'*', b'#', b'$', b'@'];

    loop {
        // 安全重置数组,替代unsafe的write_bytes
        b.fill(b' ');
        z.fill(0.0);

        let mut j = 0.0;
        while j < 6.28 {
            let mut i = 0.0;
            while i < 6.28 {
                let c = f32::sin(i);
                let d = f32::cos(j);
                let e = f32::sin(A);
                let f = f32::sin(j);
                let g = f32::cos(A);
                let h = d + 2.0;
                let D = 1.0 / (c * h * e + f * g + 5.0);
                let l = f32::cos(i);
                let m = f32::cos(B);
                let n = f32::sin(B);
                let t = c * h * g - f * e;
                let x = (40.0 + 30.0 * D * (l * h * m - t * n)) as i32;
                let y = (12.0 + 15.0 * D * (l * h * n + t * m)) as i32;
                let o = x + 80 * y;
                let N = (8.0 * ((f * e - c * d * g) * m - c * d * e - f * g - l * d * n)) as i32;

                if y > 0 && y < 22 && x > 0 && x < 80 && D > z[o as usize] {
                    z[o as usize] = D;
                    if N > 0 && N < chars.len() as i32 {
                        b[o as usize] = chars[N as usize];
                    } else {
                        b[o as usize] = b' ';
                    }
                }
                i += 0.02;
            }
            j += 0.07;
        }

        // 输出帧内容,修正越界问题
        for k in 0..1760 {
            if (k + 1) % 80 == 0 {
                handle.write_all(&[b[k], b'\n']).unwrap();
            } else {
                handle.write_all(&[b[k]]).unwrap();
            }
        }

        // 单帧完成后再更新旋转角度
        A += 0.04;
        B += 0.02;

        thread::sleep(time::Duration::from_millis(30));
        clearscreen::clear().unwrap();
    }
}

关键修改点

  • 将char数组改为u8数组,匹配原C代码的单字节字符逻辑,避免Unicode字符的内存填充问题。
  • 用fill方法安全重置数组,移除unsafe操作。
  • 修正输出循环的越界问题,调整换行逻辑为每80个字符输出换行。
  • 将旋转角度的增量移到单帧绘制完成后,保证一帧内角度稳定。
  • 将字符集向量改为全局数组,避免循环内重复创建。

内容的提问来源于stack exchange,提问作者Locu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 13:32:02