-1

I am trying to move a 6x6 pixel object in 8086 assembly, but with no luck. I would like it to move 4 pixels a second, but currently it isn't moving at all.

I would be very glad if someone could help me, because it is a for a substantial project for my computer studies finals in high school and I have got until the end of the weekend

Here is the code itself

    IDEAL
    MODEL medium

        DATASEG

    STACK 100h

    segment extra para public use16 ;Create Extra Segment that is 16 bits;
      ;(Removed the data segment for your sake, its very long pixel lists)

    CODESEG 

    ; -------------------------------
    ; change screen mode to text mode
    ; -------------------------------

    proc DrawPix
    ContLines:
        mov  cx, [LineLength]     ; How many times should the "rep movsb" should iterate
        push di         ; Save in stack the calculated position indicating the begining of the current line

        rep  movsb      ; copies bytes from si(image) to di (screen)

        pop  di         ; di was changed during the movesb. I change it back to pint to the begin of the line
        add  di, ScreenWidth ; by adding ScreenWidth (320)' I am moving the di to point to the next line
        dec  [NumOfLines]   ; Check if I wrote all the lines of the image
        jnz  ContLines    ; IF there are still pixcells to print on the screen(image not ended), loop to next line
        ret
        endp



    proc keycontrol
;check for arrow keys, and go to check arrow removed;
            jmp Shoot
    checkarrow:
        removed, irrelevant (supposed to change direction of turret)
    Exit:
    ret

    endp

    proc Shoot
    cmp [turretstate],1 ;turret facing up
    je bulletup
    cmp [turretstate],2;turret facing down
    je bulletdown
    cmp [turretstate],3;turret facing left
    je bulletleft
    cmp [turretstate],4;turret facing right
    je bulletright
    ret

    bulletup:
      not relevant for testing left movement
    bulletdown:
       not relevant for testing left movement
    bulletright:
    not relevant for testing left movement
    bulletleft:
        mov di,320*87+133
       lea si, [bullet]
       mov [LineLength],6
       mov [numOFLines],6
       call DrawPix
       ret
       endp

       proc leftbull
       pop dx
       dec dx
       mov di,320*84
       add di,dx
       lea si, [bullet]
       mov [LineLength],6
       mov [NumOfLines],6
       call DrawPix
       ret
       endp

       proc progbullets
       mov dx,0
       checkleft:
       inc dx
       cmp dx,136
       je exit1
       mov cx,87
       mov ah,0Dh
       int 10h
       cmp al,4
       jne checkleft
       push dx
       call leftbull
       exit1:
       ret
       endp
    ;---------------------------------------------;
    ;---------------------------------------------;
    start:


        Main_Loop:
        mov [sectimer], 0
        mov ah,00H
        int 1Ah
        mov [sectimer],dx
        call keycontrol
        func_Loop:
        call progbullets
        mov ah,00H
        int 1Ah
        sub dx,18
        cmp dx,[sectimer]
        jge Main_Loop
        ;call moveGame
        jmp func_Loop
        ; call the operating system to terminate this program

        mov ah,1
        int 21h
        mov ax, 4C00H
        int 21h  


    ends
    end start

The program has a starting screen, can move the turret around, and place the "bullets", but I wasn't able to make them move and it also has some odd pixels here and there. The Shoot proc is the main concern, it is supposed to go one by one on the x value (the bullet stays on the same y value), and check if the pixel is red (bullet color), and if so move it one left.

EDIT: Thanks so much for the help, I am new here and really need it. I don't have a proper debugger for gui tasm which is the system I am using, so I wasent able to do that I removed most of the unecessary stuff, but wasen't sure what else isn't necessary, since I am not sure what is the thing that dosen't work. I guess the "shoot" proc is the most relevant. The shoot only works for the left bullet, because I wanted to test it first, but it didnt work for that either

doraviv
  • 1
  • 2
  • Welcome! That's a big chunk of code you have there. Is there any way to reduce that to just the part that isn't working? – kismert May 15 '18 at 19:45
  • Add a comment before each function that details how it expects to be called... registers in, out, memory used. Then you can check where you call the functions more easily to see if something is not set up or gets overwritten. Then when you think it is ok use a debugger and single step, verifying all registers on function entry and exit. – Cmaster May 15 '18 at 19:48
  • 1
    related: https://stackoverflow.com/a/42946600/4271923, https://stackoverflow.com/a/37273073/4271923 ... edit: and also this one may be of some help: https://codereview.stackexchange.com/a/133845/110284 ... to get more help with YOUR particular code, debug it first and describe which part of code is supposed to move the bullets, whether it gets executed, and what it does instead of expected things... but if you will figure that, you will probably figure out what is the problem... – Ped7g May 15 '18 at 20:04
  • @James_Parsons: you removed a bunch of useful tags along with the incorrect `[computer-science]`. IDK why the OP tagged both TASM and emu8086, but possibly they're assembling with TASM and running the resulting binary under emu8086. It's *definitely* an x86-16 question, though, so you definitely shouldn't have removed that. – Peter Cordes May 15 '18 at 20:07
  • 1
    BTW: 4 pixels per second on 60Hz display are 15 frames of delay between +-1 pixel, unless you will do some anti-aliased bullets with sub-pixel movement accuracy. ... With the DOS timer in default 18.2Hz you will have to wait 4.55 ticks, which is more tricky to code, I would personally ditch the timer timing, and switch to VSYNC, for smooth animation and 60Hz ticking of main loop, 18.2Hz ticking is way too slow for games. – Ped7g May 15 '18 at 20:11
  • @doraviv: debugging large programs isn't really on-topic for SO. Nobody else is going to have the exact same problem in the future with all that surrounding code. It's good that you show your complete code, but you also need to use the debugger built-in to emu8086 (or any other debugger) to find out more about what *does* happen when you run your program to make this a [mcve] / http://idownvotedbecau.se/nodebugging/. The code to actually redraw anything is buried somewhere in your code under boatloads of lines of data and miscellaneous stuff, and you don't say how it should work in detail. – Peter Cordes May 15 '18 at 20:14
  • @PeterCordes Thanks for the advice. I do not have a working debugger for gui tasm, and so I wasen't able to check it. I will reduce the code – doraviv May 15 '18 at 20:28
  • 2
    Not having a debugger is the first problem you should fix. Especially for a large project, working without a debugger is like trying to build a robot blindfolded. It's often hard to figure out what small mistake is causing the total failure you see when you just run the code. You might be able to use the debugger built-in to BOCHS or DOSBOX, if you're running your code inside either of those, but that's a full-system debugger. If you actually have emu8086, it has a debugger. (Otherwise remove that tag.) – Peter Cordes May 15 '18 at 20:43
  • reduced my code significantly, thanks anyways for anyone that helped – doraviv May 15 '18 at 20:48
  • TASM (turbo assembler by Borland) has no GUI. Plus it's always sold with "turbo debugger" (td.exe) included, so just check your package. If you didn't buy it, nor you have it borrowed from school under edu-license terms, then you are participating in SW theft. It's a bit unfortunate to suggest you to use some kind of free SW few days before deadline, but if you are already a thief, steal rather properly full package including all tools and documentation. For the future just use some modern SW tools, 3/4 of SW tools today are available as free SW. – Ped7g May 15 '18 at 21:08
  • 1
    But actually debugging graphic output in turbo debugger is not that simple, learning how to use built-in debugger of some DOS emulator like BOCHS or dosbox is much more powerful and accurate. The TD has some limits, as it is dos application itself (for example pixel graphics gets corrupted when you enter the text UI of the debugger), while the emulator debugger is running "outside" of machine, not interfering with emulated machine and your running code at all. – Ped7g May 15 '18 at 21:10
  • @doraviv: nice edit, that's an improvement; thanks for taking the time to clean up your question. – Peter Cordes May 15 '18 at 23:34
  • maybe this [What is the best way to move an object on the screen?](https://stackoverflow.com/a/29579522/2521214) will help. – Spektre May 17 '18 at 07:21

1 Answers1

2

One of major problems in the shortened code is:

   push dx
   call leftbull

...

   proc leftbull
   pop dx
   dec dx

You missed the implementation detail of the call and ret instructions. They use the "stack" memory area too, so the pop dx is not reading the value stored into stack by the push dx before call, but the "return address", i.e. address of the next instruction after the call instruction.

You can fix problems like this using your own calling convention for your subroutines, where you will pass arguments in registers, like in this case just delete push dx and pop dx, because you already have the desired value in dx (but verify if you did call leftbull also from elsewhere, to fix that call to put the argument into dx too).


Other thing is, that it's a bit naive and crude approach to search the pixel data for the existing bullet. Rather reserve some space in data segment for bullet positions (depending how many bullets you can have at screen at the same time), and keep updating those positions, so you don't need to search for the current position through the pixel data.

Plus with more complex games you can have some sprites drawn over each other, so searching for pixel data in such case would fail, as the sprite "under" would be not visible = not found. But also reading video memory is extra slow, so scanning through 320 pixels is nowhere as fast as scanning through 320 bytes in data segment. And reading pixel value by int 10h service is usually another ten-fold slower than reading them directly from video memory, so your current idea is about ~200-1000 times slower than having bullet position "variables" and update bullets through those.

Reconsider your whole game schematics and main-loop algorithm, maybe try to draw for a while on a paper, what you really need stored, to maintain complete "state of world", to allow you to redraw the world from scratch every frame (somewhat following modern MVC SW architecture pattern), also those various up/down/left/right variants of code... try to parametrize that, so you can have single universal routine handling all cases, doing the different things based on the parameter of particular bullet.

I did once 2048 byte long DOS game for one code-golfing competition, so the code is not exactly most readable one, but you may still take a quick look, maybe it will inspire you in a thing or two (source is included and I was using TASM back then): http://www.pouet.net/prod.php?which=2692

Ped7g
  • 16,236
  • 3
  • 26
  • 63