掌機 - GameShell - 終極改造



基本上,司徒要感謝GameShell官方贈送這台開發測試機,讓司徒可以盡情發揮破壞的能力,而司徒打算從外殼改造開始著手,理由很簡單,因為官方設計的外殼根本無法拿來當作掌機遊玩,最基本的DPad都設計的一塌糊塗,更何況四顆ABXY按鈕,L、R按鍵就別想了,因此司徒決定設計一個經典的外殼,而眾所皆知的經典掌機就是丁果A320掌機,所以外形基本上是參考丁果A320外觀,搭配使用的軟體則是:OpenSCAD和KiCAD這兩套開源軟體,而使用的DPad、ABXY以及SS按鈕,則是依據NDSL掌機的尺寸做設計,司徒希望這樣的設計,除了可以延續丁果A320掌機的經典外殼,更可以融合NDSL的好手感,實為一石二鳥之計!

司徒使用OpenSCAD畫了A面外殼


OpenSCAD源碼

$fn = 60;

module meniscus(h=10, r=1){
    difference(){
        translate([r/2+0.1, r/2+0.1, 0]){
            cube([r+0.2, r+0.1, h+0.2], center=true);
        }
        cylinder(h=h+0.2, r=r, center=true);
    }
}

module cube_round_corner(w=10, h=10, z=10, r=1){
    difference(){
        cube([w, h, z], center=true);
        translate([(w/2)-r, (h/2)-r]){
            rotate(0){    
                meniscus(z, r);
            }
        }
        translate([(-w/2)+r, (h/2)-r]){
            rotate(90){
                meniscus(z, r);
            }
        }
        translate([(-w/2)+r, (-h/2)+r]){
            rotate(180){
                meniscus(z, r);
            }
        }
        translate([(w/2)-r, (-h/2)+r]){
            rotate(270){
                meniscus(z, r);
            }
        }
    }
}

module cube_round_all(w=10, h=10, z=10, tk=1, rad=0.3){
 difference(){
        hull(){
            sphere(rad);
            translate([w, 0, 0]){
                sphere(rad);
            }
            translate([w, h, 0]){
                sphere(rad);
            }
            translate([0, h, 0]){
                sphere(rad);
            }
            translate([0, 0, z]){
                sphere(rad);
            }
            translate([w, 0, z]){
                sphere(rad);
            }
            translate([w, h, z]){
                sphere(rad);
            }
            translate([0, h, z]){
                sphere(rad);
            }
        }
        hull(){
            translate([tk, tk, tk]){
                sphere(rad);
            }
            translate([w-tk, tk, tk]){
                sphere(rad);
            }
            translate([w-tk, h-tk, tk]){
                sphere(rad);
            }
            translate([tk, h-tk, tk]){
                sphere(rad);
            }
            translate([tk, tk, z-tk]){
                sphere(rad);
            }
            translate([w-tk, tk, z-tk]){
                sphere(rad);
            }
            translate([w-tk, h-tk, z-tk]){
                sphere(rad);
            }
            translate([tk, h-tk, z-tk]){
                sphere(rad);
            }
        }
    }
}

module screw(h=4, d=1.5, hole=0.6, aid=1){
    difference(){
        union(){
            if(aid > 0){
                translate([0, 0, -h/4]){
                    cube([d*3, 1, h/2], center=true);
                    cube([1, d*3, h/2], center=true);
                }
            }
            translate([0, 0, -(h/2)]){
                cylinder(h, d, d, center=true);
            }
        }
        cylinder(h*2, hole, hole, center=true);
    }
}

module screw_rev(h=4, d=1.5, hole=0.6, aid=1){
    difference(){
        union(){
            if(aid > 0){
                translate([0, 0, -h/4]){
                    cube([d*3, 1, h/2], center=true);
                    cube([1, d*3, h/2], center=true);
                }
            }
            translate([0, 0, 0]){
                cylinder(h, d, d, center=true);
            }
        }
        cylinder(h*2, hole, hole, center=true);
    }
}

module c_gamepad_dpad(){
    difference(){
        translate([0, 0, 0]){
            cube([25.7, 26.7, 5]);
        }
        translate([0.6, 0.6, 1.5]){
            cube([24.5, 25.5, 5]);
        }
        translate([25.7/2, 26.7/2, 0]){
            cylinder(5, 12, 12);
        }
    }

    translate([25.7/2, 26.7/2, 0]){
        ndsl_dpad();
    }

    translate([3.25, 3, 1.7]){
        screw_rev(2.9, 2, 0.6, 0);
    }
    translate([3.25, 24, 1.7]){
        screw_rev(2.9, 2, 0.6, 0);
    }
    translate([22.75, 3, 1.7]){
        screw_rev(2.9, 2, 0.6, 0);
    }
    translate([22.75, 24, 1.7]){
        screw_rev(2.9, 2, 0.6, 0);
    }
    translate([0.3, 25/2, 3]){
        rotate([0, 90, 0]){
            cube_round_corner(5, 10, 0.6, 2);
        }
    }
}

module c_gamepad_four(){
    difference(){
        translate([0, 0, 0]){
            cube([28.2, 27.7, 5]);
        }
        translate([0.6, 0.6, 1]){
            cube([27, 26.5, 5]);
        }
        translate([28.7/2, (27.7/2), 0]){
            cylinder(1, 12.7, 12.7);
        }
    }

    translate([28.7/2, 6.35, 0]){
        ndsl_four();
    }

    translate([4.2, 3.5, 1.5]){
        screw_rev(2.75, 2, 0.6, 0);
    }
    translate([4.2, 24.5, 1.5]){
        screw_rev(2.75, 2, 0.6, 0);
    }
    translate([24.5, 3.5, 1.5]){
        screw_rev(2.75, 2, 0.6, 0);
    }
    translate([24.5, 24.5, 1.5]){
        screw_rev(2.75, 2, 0.6, 0);
    }
    translate([0.3, 25/2, 3]){
        rotate([0, 90, 0]){
            cube_round_corner(5, 10, 0.6, 2);
        }
    }
}

module c_gamepad_ss(){
    difference(){
        translate([0, 0, 0]){
            cube([19.2, 16.2, 5]);
        }
        translate([2.1, 4.1, 1]){
            cube([15, 8, 5]);
        }
        translate([0.6, 0.6, 3]){
            cube([18, 15, 5]);
        }
        translate([5.5, 16.2/2, -1]){
            cylinder(5, 1.9, 1.9);
        }
        translate([13.5, 16.2/2, -1]){
            cylinder(5, 1.9, 1.9);
        }
        
        // screw
        translate([3.1, 2, 0.5]){
            cylinder(5, 0.6, 0.6);
        }
        translate([3.1, 14, 0.5]){
            cylinder(5, 0.6, 0.6);
        }
        translate([16.1, 2, 0.5]){
            cylinder(5, 0.6, 0.6);
        }
        translate([16.1, 14, 0.5]){
            cylinder(5, 0.6, 0.6);
        }
    }
}

module ndsl_dpad(){
    union(){
        difference(){
            translate([0, 0, 0]){
                cylinder(1.5, 12, 12);
            }
            translate([0, 0, 1]){
                cylinder(10, 7, 7);
            }
            cube([18.7, 6.7, 5], center=true);
            cube([6.7, 18.7, 5], center=true);
        }
        difference(){
            union(){
                // x
                translate([0, 7, 1.3]){
                    difference(){
                        cylinder(1.5, 4.8, 4.8);
                        cylinder(1.5, 4.2, 4.2);
                    }
                }
 
                // y
                translate([-7, 0, 1.3]){
                    difference(){
                        cylinder(1.5, 4.8, 4.8);
                        cylinder(1.5, 4.2, 4.2);
                    }
                }
                            
                // a
                translate([7, 0, 1.3]){
                    difference(){
                        cylinder(1.5, 4.8, 4.8);
                        cylinder(1.5, 4.2, 4.2);
                    }
                }
                            
                // b
                translate([0, -7, 1.3]){
                    difference(){
                        cylinder(1.5, 4.8, 4.8);
                        cylinder(1.5, 4.2, 4.2);
                    }
                }
            }
            translate([-6, -6, 1]){
                cube([12, 12, 5]);
            }
            translate([0, 0, 0.5]){
                cylinder(10, 7, 7);
            }
        }
    }
}

module ndsl_four(){
    difference(){
        translate([0, 7.5, 0]){
            cylinder(1, 13, 13);
        }
        
        rotate([0, 0, 45]){
            translate([0, 0, -1]){
                cylinder(10, 3.75, 3.75);
            }
            translate([10.5, 0, -1]){
                cylinder(10, 3.75, 3.75);
            }
            translate([0, 10.5, -1]){
                cylinder(10, 3.75, 3.75);
            }
            translate([10.5, 10.5, -1]){
                cylinder(10, 3.75, 3.75);
            }
        }
    }

    union(){
        // a
        translate([0, 15, 1.5]){
            rotate([0, 0, 225]){
                difference(){
                    cylinder(2, 5.3, 5.3, center=true);
                    cylinder(2, 4.7, 4.7, center=true);
                    translate([5, 0, 1]){
                        cube([3, 2.2, 5], center=true);
                    }
                }
                rotate([0, 0, 270]){
                    translate([-4.475, 0, 0]){
                        cube([1.25, 1.25, 2], center=true);
                    }
                }
            }
        }

        // b
        translate([-7.5, 7.5, 1.5]){
            rotate([0, 0, 315]){
                difference(){
                    cylinder(2, 5.3, 5.3, center=true);
                    cylinder(2, 4.7, 4.7, center=true);
                    translate([5, 0, 1]){
                        cube([3, 2.2, 5], center=true);
                    }
                }
                rotate([0, 0, 315]){
                    translate([-4.3, 0, 0]){
                        cube([1.25, 1.25, 2], center=true);
                    }
                }
                rotate([0, 0, 135]){
                    translate([-4.45, 0, 0]){
                        cube([1.25, 1.25, 2], center=true);
                    }
                }
            }
        }
        
        // x
        translate([7.5, 7.5, 1.5]){
            rotate([0, 0, 135]){
                difference(){
                    cylinder(2, 5.3, 5.3, center=true);
                    cylinder(2, 4.7, 4.7, center=true);
                    translate([5, 0, 1]){
                        cube([3, 2.2, 5], center=true);
                    }
                }
                rotate([0, 0, 0]){
                    translate([-4.375, 0, 0]){
                        cube([1.25, 1.25, 2], center=true);
                    }
                }
            }
        }
                    
        // y
        translate([0, 0, 1.5]){
            rotate([0, 0, 45]){
                difference(){
                    cylinder(2, 5.3, 5.3, center=true);
                    cylinder(2, 4.7, 4.7, center=true);
                    translate([5, 0, 1]){
                        cube([3, 2.2, 5], center=true);
                    }
                }
                rotate([0, 0, 40]){
                    translate([-4.375, 0, 0]){
                        cube([1.25, 1.25, 2], center=true);
                    }
                }
                rotate([0, 0, 318]){
                    translate([-4.375, 0, 0]){
                        cube([1.25, 1.25, 2], center=true);
                    }
                }
            }
        }
    }
}

module ndsl_ss(){
    difference(){
        cylinder(1, 3.7, 3.7);
        cylinder(10, 2, 2);
    }
    
    translate([0, 0, 1]){
        difference(){
            cylinder(1, 3.5, 3.5);
            cylinder(1, 3, 3);
        }
    }
}

module lcd(){
    difference(){
        translate([-2, 0, 0]){
            cube([70, 50, 4]);
        }
        translate([6, (50-42)/2 + 0.5, 0]){
            cube([54, 41, 10]);
        }
        translate([3, (50-46)/2, 1]){
            cube([64, 46, 10]);
        }
    }
    
    translate([-2, 49, 4]){
        cube([70, 1, 2]);
    }
    translate([-2, 0, 4]){
        cube([70, 1, 2]);
    }
    translate([-2, 1, 5.35]){
        rotate([0, 90, 0]){
            cylinder(45, 0.6, 0.6);
        }
    }
    translate([63, 1, 5.35]){
        rotate([0, 90, 0]){
            cylinder(5, 0.6, 0.6);
        }
    }
    translate([-2, 49, 5.35]){
        rotate([0, 90, 0]){
            cylinder(70, 0.6, 0.6);
        }
    }
}

// a side
module a_side(){
    difference(){
        union(){
            difference(){
                cube_round_all(122, 50, 15, 1.5, 2);
                translate([-10, -10, 9.5]){
                    cube([150, 70, 10]);
                }
                
                // lcd
                translate([(125-70)/2-2.5, 0, -2]){
                    cube([70, 50, 5]);
                }
            }
            translate([(125-70)/2-0.5, 0, -2]){
                lcd();
            }
        }
        
        // mini usb
        translate([120, 17, 8]){
            rotate([0, 90, 0]){
                cube_round_corner(6, 8, 10, 2);
            }
        }
        
        // dpad
        translate([0, (50-27)/2-3.5, -2]){
            cube([25.7, 25, 5]);
        }
                
        // four
        translate([94.4, (50-28.5)/2-4.35, -2]){
            cube([27.25, 28, 5]);
        }
        
        // ss
        translate([5.75, 36, -2]){
            cube([19, 14, 5]);
        }
        
        // ss
        translate([97, 36, -2]){
            cube([19, 14, 5]);
        }
    }

    translate([26.25, (50-27)/2-3.5, -2]){
         rotate([0, 0, 90]){
            c_gamepad_dpad();
        }
    }
    translate([94.4, 34.5, -2]){
        rotate([0, 0, 270]){
            c_gamepad_four();
        }
    }
    translate([5.75, 34, -2]){
        c_gamepad_ss();
    }
    translate([97, 34, -2]){
        c_gamepad_ss();
    }

    // screw for core board
    translate([3.75, 3, 3.5]){
        screw_rev(10, 2.5, 0.6, 0);
    }
    translate([3.75, 44.5, 3.5]){
        screw_rev(10, 2.5, 0.6, 0);
    }
    // holder
    translate([22.25, -1, -1.5]){
        difference(){
            cube([3.5, 3, 11]);
            translate([0, 1, 10]){
                cube([3.5, 2, 5]);
            }
        }
    }
    translate([24.35, 47, -2]){
        difference(){
            union(){
                cube([2, 2.5, 11.5]);
                translate([0, -0.5, 3]){
                    cube([2, 5, 8.5]);
                }
            }
            translate([0, -1, 10.5]){
                cube([2, 2, 5]);
            }
        }
    }

    // screw for keyboard board
    translate([120-0.5, 4, 1]){
        screw_rev(6, 2.5, 0.6, 0);
    }
    translate([120-0.5, 45.5, 1]){
        screw_rev(6, 2.5, 0.6, 0);
    }
    // holder
    translate([120-25, -1, -1.5]){
        difference(){
            cube([5, 3, 6.5]);
            translate([0, 2, 5.5]){
                cube([5, 2, 5]);
            }
        }
    }
    translate([120-25.5, 48, -2]){
        difference(){
            cube([3.1, 2.5, 7]);
            translate([0, 0, 6]){
                cube([3.1, 1, 5]);
            }
        }
    }
}

// b side
module b_side(){
    difference(){
        cube_round_all(122, 50, 15, 1.5, 2);
        translate([-5, -5, -5]){
            cube([150, 100, 10]);
        }
        
        
        translate([-5, -5, 10]){
            cube([150, 100, 50]);
        }
    }
    
    translate([-2, 10, 12]){
        rotate([0, 90, 0]){
            cube([6, 8, 1.5]);
        }
    }
}

a_side();
//b_side();
//lcd();

裡面構造


接著使用3D印表機列印


裡面構造


LCD部分由於PCB的關係(沒有四面螺絲可以使用),司徒最終使用卡扣的方式固定


這個卡扣設計的還不錯


接著是比較麻煩的部分,因為需要送洗PCB以及焊接PCB,當然使用者也可以使用既有的掌機改造


NDSL的DPad、ABXY和SS按鈕


1mm x 4螺絲


接著鎖上PCB


固定核心板


美美的正面照(由於司徒目前只有1mm x 5的螺絲,所以目前有穿刺的狀況)


吻合的USB孔位


耳機孔位會由中間層來固定


內縮的MicroSD


定位孔花了相當多的時間設計以及測試


LCD置中


遊戲畫面