JavaScript Chip8仿真器碰撞检测问题

时间:2018-03-21 02:43:08

标签: javascript emulation

我正在使用JavaScript制作Chip8模拟器。除了2件事之外,我大部分时间都已完成。

  1. 主要的性能和图形问题。循环执行速度不够快,因此屏幕闪烁太慢,使游戏变得不那么顺畅。

  2. 碰撞检测。 Chip8通过使用XOR确定白色像素是否被覆盖为黑色来检测碰撞,然后将V [15]设置为1.问题是,我无法弄清楚如何比较像素,两个,我有不知道为什么碰撞检测件的“测试”版本不起作用。 Pong(我的默认游戏)中的块只是相互通过。

  3. 我想知道如何解决问题#2,因为这会影响模拟器本身的核心。如何进行有效的碰撞检测功能,如果发生碰撞,将V [15]的值设置为1?

    这是代码。

    <input type="text" size="40" onkeypress="trackkey(event)"></input><br />
    <div id="memory" /><div id="debugscreen" />
    <canvas id="screen" width="640" height="320" style="border:1px solid #000000;">
    </canvas>
    <script>
      function trackkey(event) {
      var x = event.which || event.keyCode;
      var y=0;
    //    alert(x);
        switch(x){
          case 49://1, 1
            y=1;
            break;
          case 50://2, 2
            y=2;
            break;
          case 51://3, 3
            y=3;
            break;
          case 52://4, 0xc
            y=0xc;
            break;
          case 113://q, 4
            y=4;
            break;
          case 119://w, 5
            y=5;
            break;
          case 101://e, 6
            y=6;
            break;
          case 114://r, 0xD
            y=0xD; 
            break;
          case 97://a, 7
            y=7;
            break;
          case 115://s, 8
            y=8;
            break;
          case 100://d, 9
            y=9;
            break;
          case 102://f, 0xe
            y=0xE;
            break;
          case 122://z, 0xA
            y=0xA;
            break;
          case 120://x, 0 
            y=0;
            break;
          case 99://c, 0xB
            y=0xB;
            break;
          case 122://v, 0xF
            y=0xF;
            break;
    
          default:
            y=50;
            break;
        }
        y-=1;
        if(y!=49){
            pressedKey=y;keyDown=true;
            for(var i=0;i<16;i++){
              if(i!=y){
              key[i]=0;
              }else{key[i]=1;}
    
      }
        }
        console.log(keyDown+" "+pressedKey+" "+key);
      }
      //specs and variables
      var opcode;
      var memory=new Array(4096);
      var V=new Array(16);
      var I;
      var pc;
      var buffer;
      var gfx=new Array(64*32);
      var delay_timer;
      var sound_timer;
      var stack=new Array(16);
      var sp;
      var key=new Array(16);
      var drawFlag;
      var text=[
      0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
      0x20, 0x60, 0x20, 0x20, 0x70, // 1
      0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
      0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
      0x90, 0x90, 0xF0, 0x10, 0x10, // 4
      0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
      0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
      0xF0, 0x10, 0x20, 0x40, 0x40, // 7
      0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
      0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
      0xF0, 0x90, 0xF0, 0x90, 0x90, // A
      0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
      0xF0, 0x80, 0x80, 0x80, 0xF0, // C
      0xE0, 0x90, 0x90, 0x90, 0xE0, // D
      0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
      0xF0, 0x80, 0xF0, 0x80, 0x80  // F
      ];
      //game loop
      main();
    
      function main(){
        //setupGraphics();
        //setupInput();
        setKeys();
        loadGame();
        initialize();
        drawGraphics();
        setInterval(gameLoop, 0.000016);
      }
    
      function gameLoop(){
    
        emulateCycle();
        if(drawFlag){
          drawGraphics();
          setKeys();//store key press state (press and release)
        }
    
      }
    
      //store key press state
      function setKeys(){
      }
    
      //initialize
      function initialize(){
    
        pc=0x200;
        opcode=0;
        I=0;
        sp=0;
        //clear();console.log("clear");
        for(var i=0;i<0x10;i++){
          V[i]=0;
        }
        for(var i=0;i<80;i++){
          memory[i]=text[i];
        }
        for(var i=0;i<buffer.length;i++){
          memory[i+512]=buffer[i];
        }
    
        delay_timer=0;
        sound_timer=0;
      }
    
      //load program
      function loadGame(){
        buffer=[106,2,107,12,108,63,109,12,162,234,218,182,220,214,110,0,34,212,102,3,104,2,96,96,240,21,240,7,48,0,18,26,199,23,119,8,105,255,162,240,214,113,162,234,218,182,220,214,96,1,224,161,123,254,96,4,224,161,123,2,96,31,139,2,218,182,141,112,192,10,125,254,64,0,125,2,96,0,96,31,141,2,220,214,162,240,214,113,134,132,135,148,96,63,134,2,97,31,135,18,70,2,18,120,70,63,18,130,71,31,105,255,71,0,105,1,214,113,18,42,104,2,99,1,128,112,128,181,18,138,104,254,99,10,128,112,128,213,63,1,18,162,97,2,128,21,63,1,18,186,128,21,63,1,18,200,128,21,63,1,18,194,96,32,240,24,34,212,142,52,34,212,102,62,51,1,102,3,104,254,51,1,104,2,18,22,121,255,73,254,105,255,18,200,121,1,73,2,105,1,96,4,240,24,118,1,70,64,118,254,18,108,162,242,254,51,242,101,241,41,100,20,101,0,212,85,116,21,242,41,212,85,0,238,128,128,128,128,128,128,128,0,0,0,0,0];
      }
    
      //clear display
      function clear(){
        for(var i=0;i<gfx.length;i++){
          gfx[i]=0;
        }
        drawFlag=true;
      }
    
      //draw
      function draw(x, y, h){
        var coordinates;
        coordinates=y*64+x;
        for(var j=0;j<h;j++){
          for(var i=0;i<8;i++){
    //          if((coordinates+i+64*j)%64!=0){//console.log(gfx[coordinates+i+64*j]==1&&parseInt(parseInt(memory[(I+j)]).toString(2)[i])==0);
              if(gfx[coordinates+i+64*j]==1&&parseInt(parseInt(memory[(I+j)]).toString(2)[i])==0){V[0xF]=1;}else{V[0xF]=0;}
    //            console.log(V[0xF]);
            gfx[coordinates+i+64*j]=parseInt(parseInt(memory[(I+j)]).toString(2)[i]);
    //        }else{i=8;}
          }
        }
        drawFlag=true;
      }
    
      //draw graphics
      function drawGraphics(){
        V[0xF]=0;
        for(var i=0;i<gfx.length;i++){
            var c = document.getElementById("screen");
            var ctx = c.getContext("2d");
            ctx.beginPath();
            if(gfx[i]==1){ctx.fillStyle = "white";}else{ctx.fillStyle = "black";}
            ctx.fillRect(i%64*10, Math.floor(i/64)*10, 10, 10);
            ctx.stroke();
          }
    //    clear();
        drawFlag=false;
      }
    
      //emulate cycle
      function emulateCycle(){
    //    debugger;
        opcode=0;
        opcode = memory[pc] << 8 | memory[pc + 1];
        switch(opcode&0xF000){
          //0x0NNN not needed
          case 0x0000: //0x00E0 and 0x00EE
            switch(opcode&0x000F){
              case 0x0000:
                clear();//console.log("clear");//clear display
                drawFlag=true;
                pc+=2;
                break;
              case 0x000E:
                //return from subroutine
                pc=stack[sp-1];
                sp=sp-1;
                pc+=2;
                break;
            }   
            break;
          case 0x1000://goto subroutine
            pc = opcode & 0x0FFF;
            break;
          case 0x2000://call subroutine
            stack[sp]=pc;
            sp++;
            pc=opcode & 0x0FFF;
            break;
          case 0x3000://skip next instruction if Vx==NN
            if(V[(opcode>>8)&0x000F].toString()==(opcode&0x00FF).toString()){
              pc+=2;
            }
            pc+=2;
            break;
          case 0x4000://skip next instruction if Vx!=NN
            if(V[(opcode>>8)&0x000F]!=opcode&0x00FF){
              pc+=2;
            }
            pc+=2;
            break;
          case 0x5000://skip next instruction if Vx==Vy
            if(V[(opcode>>8)&0x000F]==V[(opcode>>4)&0x000F]){
              pc+=2;
            }
            pc+=2;
            break;
          case 0x6000://set Vx to NN
            V[(opcode>>8)&0x000F]=opcode&0x00FF;
            //alert(V[(opcode>>8)&0x000F]);
            pc+=2;
            break;
          case 0x7000://Vx+=NN
            V[(opcode>>8)&0x000F]+=opcode&0x00FF;
            pc+=2;
            break;
          case 0x8000:
            switch(opcode&0x000F){
              case 0x0000://Vx=Vy
                V[(opcode>>8)&0x000F]=V[(opcode>>4)&0x000F];
                pc+=2;
                break;
              case 0x0001://Vx=Vx|Vy
                V[(opcode>>8)&0x000F]=V[(opcode>>8)&0x000F]|V[(opcode>>4)&0x000F];
                pc+=2;
                break;
              case 0x0002://Vx=Vx&Vy
                V[(opcode>>8)&0x000F]=V[(opcode>>8)&0x000F]&V[(opcode>>4)&0x000F];
                pc+=2;
                break;
              case 0x0003://Vx=Vx^Vy
                V[(opcode>>8)&0x000F]=V[(opcode>>8)&0x000F]^V[(opcode>>4)&0x000F];
                pc+=2;
                break;
              case 0x0004://Vx+=Vy
                if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])){
                  V[0xF] = 1; //carry
                }else{
                  V[0xF] = 0;
                  V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
                } 
                pc+=2;
                break;
              case 0x0005://Vx-=Vy
                if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])){
                  V[0xF] = 1; //carry
                }else{
                  V[0xF] = 0;
                  V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
                } 
                pc+=2;
                break;
              case 0x0006://Vx=Vy=Vy>>1
                V[0xF]=V[(opcode>>4)&0x000F]&0x000F;
                V[(opcode>>4)&0x000F]=V[(opcode>>4)&0x000F]>>1;
                V[(opcode>>8)&0x000F]=(opcode>>4)&0x000F;
                pc+=2;
                break;
              case 0x0007://Vx=Vy-Vx
                if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8])){
                  V[0xF] = 1; //carry
                }else{
                  V[0xF] = 0;
                  V[(opcode & 0x00F0) >> 4]=V[(opcode & 0x0F00) >> 8]-V[(opcode & 0x00F0) >> 4];
                } 
                pc+=2;
                break;
              case 0x000E://Vx=Vy=Vy<<1
                V[0xF]=V[(opcode & 0x0F00) >> 8] >> 7;
                V[(opcode>>4)&0x000F]=V[(opcode>>4)&0x000F]<<1;
                V[(opcode>>8)&0x000F]=V[(opcode>>4)&0x000F];
                pc+=2;
                break;
            }
            break;
          case 0x9000://if(Vx!=Vy){skip}
            if(V[(opcode>>8)&0x000F]!=V[(opcode>>4)&0x000F]){
              pc+=2;
            }
            pc+=2;
          case 0xA000://I=NNN
            I=opcode&0x0FFF;
            pc+=2;
            break;
          case 0xB000://I=NNN+V0
            pc=(opcode&0x0FFF)+V[0];
            break;
          case 0xC000://Vx=random&NN
            V[(opcode>>8)&0x000F]=Math.floor((Math.random() * 255))&((opcode)&0x00FF);
            pc+=2;
            break;
          case 0xD000://DXYN draw(Vx, Vy, N)
            V[0xF] = 0x0;
            draw(V[(opcode>>8)&0x000F], V[(opcode>>4)&0x000F], (opcode)&0x000F);
    
            pc+=2;
            break;
          case 0xE000://keypad
            switch(opcode & 0x00FF){// EX9E: Skips the next instruction if the key stored in VX is pressed
              case 0x009E:
                if(parseInt(key[V[(opcode & 0x0F00) >> 8]]) != 0){
    //      alert();
            pressedKey=null;
            keyDown=false;
                  pc+=2;
                }else{}
                pc+=2;
                break;
              case 0x00A1:
                if(parseInt(key[V[(opcode & 0x0F00) >> 8]]) == 0){
    //      alert();
            pressedKey=null;
            keyDown=false;
                  pc+=2;
                }else{}
                pc+=2;
                break;
            }
            break;
          case 0xF000:
            switch(opcode & 0x00FF){
              case 0x0007:
                V[(opcode>>8)&0x000F]=delay_timer;
                pc+=2;
                break;
              case 0x000A:
                if(keyDown==true){
                    V[(opcode>>8)&0x000F]=pressedKey;pc+=2;
                }else{alert("PAUSE");}
                break;
              case 0x0015:
                delay_timer=V[(opcode>>8)&0x000F];
                pc+=2;
                break;
              case 0x0018:
                sound_timer=V[(opcode>>8)&0x000F];
                pc+=2;
                break;
              case 0x001E:
                I+=V[(opcode>>8)&0x000F]; 
                pc+=2;
                break;
              case 0x0029:
                I=V[(opcode>>8)&0x000F]*5;
                pc+=2;
                break;
              case 0x0033:
                memory[I]     = V[(opcode & 0x0F00) >> 8] / 100;
                memory[I + 1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
                memory[I + 2] = (V[(opcode & 0x0F00) >> 8] % 100) % 10;
                pc += 2;
                break;
              case 0x0055:
                for (var i = 0; i <= ((opcode & 0x0F00) >> 8); i+=2){
                  memory[I + i] = V[i];
                  I++;
                }
                pc+=2;
                break;
              case 0x0065:
    
                for (var i = 0; i <= ((opcode & 0x0F00) >> 8); i+=2){
                  V[i] = (memory[I+i]<<8)&memory[I+(i+1)];
                  I++;
                }
                pc += 2;
                break;
            }     
            break;
          default:
            console.log("UNSUPPORTED OPCODE- "+(opcode).toString(16));console.log("");
            break;
          }
    //    console.log(opcode.toString(16));
        if(delay_timer > 0){delay_timer-=1;}
        if(sound_timer > 0){if(sound_timer == 1){console.log("BEEP!");sound_timer-=1;}}
    //    keyDown=false;
    //    pressedKey=null;
      }
    
    </script>
    

0 个答案:

没有答案