Author Topic: Enemies Freezing after another enemy is shot? (SOLVED)  (Read 5070 times)

0 Members and 1 Guest are viewing this topic.

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Enemies Freezing after another enemy is shot? (SOLVED)
« on: May 08, 2012, 10:55:35 pm »
PROBLEM SOLVED, THANK YOU ALL FOR INPUT!

So I'm working on my game, and I've run into a problem I can't seem to figure out. When there are multiple enemies, sometimes when I kill one, the others freeze in place, and will not disappear if I shoot it, and it's driving me crazy as to why! If you run the program attached, you can see the problem in the 2nd or 3rd round. I'm pretty sure it has to do with this segment of code:
Spoiler For Spoiler:
:For(G,1,I)
:If pxl-Test({L2+(G*4)},{L2+(G*4)+1})
:For(θ,1,U)
:If {L2+(G*4)}=({L1+(θ*4)}) or ({L2+(G*4)}=({L1+(θ*4)}-1))
:If {L2+(G*4)+1}=({L1+(θ*4)+1}) or ({L2+(G*4)+1}=({L1+(θ*4)+1}-1))
:{L1+(θ*4)+2}-100→{L1+(θ*4)+2}
:0→r1
:If {L1+(θ*4)+2}=0 and (U≠0)
:S+10→S
:100→{L1+(θ*4)+2}
:Pxl-Off({L1+(θ*4)},{L1+(θ*4)+1})
:Pxl-Off({L1+(θ*4)},{L1+(θ*4)+1}-1)
:Pxl-Off({L1+(θ*4)}-1,{L1+(θ*4)+1})
:Pxl-Off({L1+(θ*4)}-1,{L1+(θ*4)+1}-1)
:5→{L1+(θ*4}→{L1+(θ*4)+1}
:r1+1→r1
:End:End
:End:End
:U-r1→U
:
:{L2+(I*4)}→{L2+(G*4)}
:{L2+(I*4)+1}→{L2+(G*4)+1}
:{L2+(I*4)+2)→{L2+(G*4)+2}
:0→{L2+(I*4)}→{L2+(I*4)+1}→{L2+(I*4)+2}
:I-1→I
:Else
:Pxl-On({L2+(G*4)},{L2+(G*4)+1})
:End:End

I appreciate any help! I doubt anyone will take the time to look through the code, but if you could run it and maybe make a suggestion as to what it is, It'd help me a lot!

EXTRA INFO:
Arrow keys to move, 2nd to shoot, clear to end game
I = Bullet count
G = Which bullet
U = Zombie count
θ = Which zombie
r1 = Just a temporary variable so the code runs through for each zombie/bullet and THEN the zombie count is decreased
L1 = zombie array
L2 = bullet array
« Last Edit: September 04, 2012, 04:17:38 pm by Derf321 »

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot?
« Reply #1 on: May 11, 2012, 04:55:21 pm »
Halp please :c

Offline shmibs

  • しらす丼
  • Administrator
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2132
  • Rating: +281/-3
  • try to be ok, ok?
    • View Profile
    • shmibbles.me
Re: Enemies Freezing after another enemy is shot?
« Reply #2 on: May 13, 2012, 01:41:56 pm »
sorry that nobody has gotten back to you, yet. it might be because the section of code you posted had messed up tokens. here's what it should be:
Code: [Select]
:For(G,1,I)
:If pxl-Test({L2+(G*4)},{L2+(G*4)+1})
:For(θ,1,U)
:If {L2+(G*4)}=({L1+(θ*4)}) or ({L2+(G*4)}=({L1+(θ*4)}-1))
:If {L2+(G*4)+1}=({L1+(θ*4)+1}) or ({L2+(G*4)+1}=({L1+(θ*4)+1}-1))
:{L1+(θ*4)+2}-100→{L1+(θ*4)+2}
:0→r1
:If {L1+(θ*4)+2}=0 and (U≠0)
:S+10→S
:100→{L1+(θ*4)+2}
:Pxl-Off({L1+(θ*4)},{L1+(θ*4)+1})
:Pxl-Off({L1+(θ*4)},{L1+(θ*4)+1}-1)
:Pxl-Off({L1+(θ*4)}-1,{L1+(θ*4)+1})
:Pxl-Off({L1+(θ*4)}-1,{L1+(θ*4)+1}-1)
:5→{L1+(θ*4}→{L1+(θ*4)+1}
:r1+1→r1
:End:End
:End:End
:U-r1→U
:
:{L2+(I*4)}→{L2+(G*4)}
:{L2+(I*4)+1}→{L2+(G*4)+1}
:{L2+(I*4)+2)→{L2+(G*4)+2}
:0→{L2+(I*4)}→{L2+(I*4)+1}→{L2+(I*4)+2}
:I-1→I
:Else
:Pxl-On({L2+(G*4)},{L2+(G*4)+1})
:End:End

i don't have time to look over it right now, as i'm about to walk out the door, but hopefully the bump will catch people's attention.

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot?
« Reply #3 on: May 20, 2012, 03:10:47 am »
Days later and I'm still confused by it. I've tried so many things, to no avail :c

Offline defmenge

  • LV3 Member (Next: 100)
  • ***
  • Posts: 40
  • Rating: +5/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot?
« Reply #4 on: May 20, 2012, 05:32:54 am »
Hello Derf,

now, I haven't looked through the code yet, and I wasn't really able to figure out how to play this (didn't know how to kill zombies). It would probably help if you explained the relevant variables and buffers in the code segment, such as I, U, G, θ and r1, among others. However, I already have a theory about this, though I might be wrong:

I have had a similar problem with a project of my own previously, and assuming the enemies freeze the moment another one gets killed, you might be doing something wrong in the code that removes enemies from the buffer when they get killed. An enemy "freezing" could have several causes: forgetting to erase an enemy from the screen buffer, or incorrectly/not moving backwards the remaining enemy entries in the buffer when one is removed (in my case it was the latter, causing enemies to turn invisible and randomly freeze and warp around when one was killed).

For debugging purposes, you could try outputting the buffer index of an enemy when you kill it, and check if the problem only occurs on enemies with a certain index, so you can narrow down the randomness of a "sometimes-occuring" bug to specific criteria that must be met to reproduce the problem.

Best of luck with debugging your project,
~ defmenge
« Last Edit: May 20, 2012, 05:34:19 am by defmenge »
Spoiler For DROD8x:
Status: Pre-Alpha "ROACHIE" - Progress: 20%
[=====] Graphics: 100% (full greyscale tileset)
[==== ] Tilemapping: 80% (maps load successfully, additional tile data not implemented yet)
[=    ] Storage formats: 20% (planned: segmentable holds, composed of levels, made of up to [presumably] 8x8 rooms)
[==   ] Monsters: 40% (roaches and roach queen AI working; planned: eyes, wubbas, golems and possibly more)
[     ] Gameplay Elements: 0% (walls and floors only)
[     ] GUI: 0% (very bare in-game GUI)
[=    ] Editor: 20% (integrated basic editor)
Project is currently on hold due to lots of homework and tests.

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #5 on: May 21, 2012, 04:30:51 pm »
I have had a similar problem with a project of my own previously, and assuming the enemies freeze the moment another one gets killed, you might be doing something wrong in the code that removes enemies from the buffer when they get killed. An enemy "freezing" could have several causes: forgetting to erase an enemy from the screen buffer, or incorrectly/not moving backwards the remaining enemy entries in the buffer when one is removed (in my case it was the latter, causing enemies to turn invisible and randomly freeze and warp around when one was killed).
It's 2nd to shoot (also included the more necessary info in first post)
And yes, the enemy freezes as soon as another gets killed. I don't think its a problem with erasing from the buffer, as it works for other zombies, and I move backwards the remaining enemies after the loops, so it shouldnt interfere.
Also, I appreciate the reply!

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #6 on: September 01, 2012, 02:00:25 pm »
Narrow down the randomness of a "sometimes-occuring" bug to specific criteria that must be met to reproduce the problem.

Now that I'm back to school, I've continued working on the problem. I figured out that the bug occurs if I shoot the enemies out of order. Like if theres enemy 1, 2 and 3, if I kill them out of order like 1 then 3, #3 will be frozen in place, and it respawns at a different place (figured out it was spawning 65k spaces away out of map). I think somethings happening and its running code for the wrong zombie. Like if a piece of code for turning off pixels and moving the zombies x/y variables to another place is supposed to run for zombie #3, it instead turns off the pixels and assigns the variables to zombie #2. It may be more clear if you run it yourself, heres the newest version of the game, with diagnostic variables on screen for each zombies health (starts at 100, for now when it gets hit by a bullet it changes to 0, then after the score is processed it changes to 101)

Offline MGOS

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 336
  • Rating: +95/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #7 on: September 01, 2012, 04:11:43 pm »
Ok, I was skimming the code and found some stuff (idk if it is related to the problem, but I thought of pointing it out)
I couldn't find the main mistake though.

Code: [Select]
Lbl DIFF1
0→A→B→C→S→T→R→U→D→I→θ→G→{L1}→{L2}

storing something into a Ram location pointed to and will return the address of that location, not the value.

You're basically doing that - which is not what you want:
Code: [Select]
0→{L1}
L1→{L2}

then, the elses here make absolutely no sense to me:
Code: [Select]
:If K=15
:Goto DIE:End
:If K=33
:0→L:Else:End
:If K=34
:1→L:Else:End
:If K=26
:2→L:Else:End
:If K=16
:3→L:Else:End

You could also use a LUT and the inData( Command.

Z isn't used anywhere else than here, so that can also do weird behaviour:
Code: [Select]
If K=47 and (Z=0):1→R:End
Use + instead of "or" and * instead of "and" in when doing conditionals, those are bitwise operations.
Code: [Select]
If {L1+(θ*4)}=(X+1) or ({L1+(θ*4)}=(X-2)) or ({L1+(θ*4)}=X) or ({L1+(θ*4)}=(X-1)) or ({L1+(θ*4)}=(X+2))
Spoiler For optimization:
You can optimize calculations by changing the order to avoid parenthesis:

Code: [Select]
If {L2+(G*4)+2}=1
becomes
If {G*4+2+L2}=1

subtracting the value and checking if 0 is more optimized than checking for equality, so:
Code: [Select]
!If {G*4+2+L2}-1
when you need to perform many same/similar calculations, just store the value in a variable the first time and use the variable.
Code: [Select]
Pxl-Off({L1+(θ*4)},{L1+(θ*4)+1})
Pxl-Off({L1+(θ*4)},{L1+(θ*4)+1}-1)
Pxl-Off({L1+(θ*4)}-1,{L1+(θ*4)+1})
Pxl-Off({L1+(θ*4)}-1,{L1+(θ*4)+1}-1)
becomes
Pxl-Off({θ*4+L1→F},{F+1})
Pxl-Off({F},{F+1}-1)
Pxl-Off({F}-1,{F+1})
Pxl-Off({F}-1,{F+1}-1)


Some tips for bug finding:
  • Comment out anything you know that is working
  • Display anything related to the stuff that isn't working right as debugging data
  • Try to split the code in several files, for example one with routines, one with the menu screen etc. That will clean it upü a bit and makes it easier to locate/jump to errors.
« Last Edit: September 04, 2012, 12:09:18 pm by MGOS »

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #8 on: September 03, 2012, 10:12:47 pm »
.
Code: [Select]
Lbl DIFF1
0→A→B→C→S→T→R→U→D→I→θ→G→{L1}→{L2}

Oh I see, should I use the Fill( command to zero out the ram? I converted this program from BASIC because I realized it was getting to slow, hence some errors =/

The following code probably doesn't make much sense because I havent implemented other guns yet =P  The L variable stands for "which gun is selected" and, pressing key 15 (CLEAR) ends the game quickly for a quick exit to the game.
Code: [Select]
:If K=15
:Goto DIE:End     
:If K=33
:0→L:Else:End
:If K=34
:1→L:Else:End
:If K=26
:2→L:Else:End
:If K=16
:3→L:Else:End

What is a LUT and what does inData do? I looked it up, but the definition doesnt make much sense to me.

The Z variable was actually left-over from when I changed around variables. Its supposed to check if theres no zombies before you can start another round, but I left it so you can restart a round while theres zombies out for testing purposes. (The real variable is now U for zombie count).
Code: [Select]
If K=47 and (Z=0):1→R:End
I never knew about the "+" and "*" operations, I'll look into it!
Your optimizations also are very, very useful. I'll optimize the whole program after I figure out this error.

I'll make a version of the program that is easier for you guys to read now, commenting on it and all.

Offline MGOS

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 336
  • Rating: +95/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #9 on: September 04, 2012, 04:25:26 am »
Oh I see, should I use the Fill( command to zero out the ram?
No, just do 0→{L2}

What is a LUT and what does inData do?
LUT stands for Look-up-table. It is basically just a constant array with values. You can get each value by accessing the data with an index. That is usually a lot faster than having a calculation for it.

Example:
Code: [Select]
{0,1,4,9,16,25,36,49,64,81,100,121,144,169,196,225}→GBD1  ; a LUT with the squares of 0-15
...
instead of a calculation like
A²→B
you can use the LUT:
{A+GBD1}→B

The speed difference isn't that big in such an easy example, but with the complexity of the calculation you can avoid it gets more notable.
Other examples for LUTs: Frequencies for Music, characteristics/properties of different weapons/armor/enemies, ...

You have to make sure that the index doesn't get out of range, otherwise is it'll do weird stuff, e. g when A is 16 or larger, it'll still read the data after the LUT.

You can use an LUT also the other way round. Axe provides the function inData() for that.

Quote from: Axe Command List
inData(BYTE,PTR)     Searches for BYTE in the zero-terminated data. If found, it returns the position it was found in (starting at 1). If not found, 0 is returned.

Zero-terminated means, that the last value of the LUT has to be 0 respectively the first 0 in the LUT is considered as the end.

Say, at the beginning of the code we have a LUT with our keys, ending with 0:
Code: [Select]
{33,34,26,16,0}→GBD1at the point where we need the data, we use inData().
Code: [Select]
If inData(K,GBD1)→F   ; if the key is one of the weapon selectors
F-1→L         ; take this value (1-4) and subtract 1 (then we have 0-3) and store it in L.
End
optimized to save a variable:
Code: [Select]
If inData(K,GBD1)   
-1→L   ; that is the subtraction minus sign, same as above. It subtracts from the last evaluated expression, which is "inData"
End


I never knew about the "+" and "*" operations
I'm sure you know them "+" does add and "*" does multiply.  :P

But for conditions they can be used as well:
"+" is "or"
(cond 1) + (cond 2)
When either of the conditions is non-zero, the sum will be non-zero. (non-zero means "true", zero is "false")
Attention! If one of the conditions is negative, they might add up to 0 too!

"*" is "and"
(cond 1) * (cond 2)
When either of the conditions is zero, the product is zero. So all the conditions have to be non-zero, to make the whole statement non-zero.

I hope that cleared things up a bit.
« Last Edit: September 04, 2012, 04:28:17 am by MGOS »

Offline Runer112

  • Project Author
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2289
  • Rating: +639/-31
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #10 on: September 04, 2012, 11:53:07 am »
Code: [Select]
Lbl DIFF1
0→A→B→C→S→T→R→U→D→I→θ→G→{L1}→{L2}

storing something into a Ram location pointed to and will return the address of that location, not the value.

You're basically doing that - which is not what you want:
Code: [Select]
0→{L1}
L1→{L2}

Only applies if the pointer is not a constant! :P L2 is a constant, so that part of his code is fine.


then, the elses here make absolutely no sense to me:
Code: [Select]
:If K=15
:Goto DIE:End
:If K=33
:0→L:Else:End
:If K=34
:1→L:Else:End
:If K=26
:2→L:Else:End
:If K=16
:3→L:Else:End

You could also use a LUT and the inData( Command.

Also, I think you want 18, not 16, for the "3" key.


Use + instead of "or" and * instead of "and" in when doing conditionals, those are bitwise operations.
Code: [Select]
If {L1+(θ*4)}=(X+1) or ({L1+(θ*4)}=(X-2)) or ({L1+(θ*4)}=X) or ({L1+(θ*4)}=(X-1)) or ({L1+(θ*4)}=(X+2))

In a long chain of or's like this, substituting them for +'s is a good optimization. But if you have any and's, I would stick with the bitwise logic operators and not substitute them for arithmetic operators. In any case I wouldn't substitute and with *, because multiplication is not a native operation on the z80 and takes much longer than bitwise and.


What is a LUT and what does inData do?
LUT stands for Look-up-table. It is basically just a constant array with values. You can get each value by accessing the data with an index. That is usually a lot faster than having a calculation for it.

Example:
Code: [Select]
{0,1,4,9,16,25,36,49,64,81,100,121,144,169,196,225}→GBD1  ; a LUT with the squares of 0-15
...
instead of a calculation like
A²→B
you can use the LUT:
{A+GBD1}→B

Remember, the syntax to create a list of data in Axe is different from that in TI-BASIC:
Data(0,1,4,9,16,25,36,49,64,81,100,121,144,169,196,225)→GBD1

(Data( is really the ∆List( token)


You can use an LUT also the other way round. Axe provides the function inData() for that.

Quote from: Axe Command List
inData(BYTE,PTR)     Searches for BYTE in the zero-terminated data. If found, it returns the position it was found in (starting at 1). If not found, 0 is returned.

Zero-terminated means, that the last value of the LUT has to be 0 respectively the first 0 in the LUT is considered as the end.

Say, at the beginning of the code we have a LUT with our keys, ending with 0:
Code: [Select]
{33,34,26,16,0}→GBD1at the point where we need the data, we use inData().
Code: [Select]
If inData(K,GBD1)→F   ; if the key is one of the weapon selectors
F-1→L         ; take this value (1-4) and subtract 1 (then we have 0-3) and store it in L.
End
optimized to save a variable:
Code: [Select]
If inData(K,GBD1)  
-1→L   ; that is the subtraction minus sign, same as above. It subtracts from the last evaluated expression, which is "inData"
End

There's currently a bit of an issue with this code that may be solved in the next version of Axe. The issue is that, if K happens to be 0, inData(K,GDB1) will return the position of the terminating zero in GDB1 which is 5, instead of the expected value of 0 for no match. Until then, the best fix for this is to add one to all the key values in GDB1 (and remember that the "3" key is 18, not 16) and do inData(K+1,GDB1).

Also, list syntax! :P


But otherwise good job helping out MGOS, it's always nice to see people willing to help others transition to Axe. :)
« Last Edit: September 04, 2012, 11:56:28 am by Runer112 »

Offline MGOS

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 336
  • Rating: +95/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #11 on: September 04, 2012, 12:03:19 pm »
Only applies if the pointer is not a constant! :P L2 is a constant, so that part of his code is fine.
Whoa, didn't know that!  :)

Remember, the syntax to create a list of data in Axe is different from that in TI-BASIC:
Data(0,1,4,9,16,25,36,49,64,81,100,121,144,169,196,225)→GBD1
Stupid mistake  :banghead:

And for the "3"-key mistake: I just copied from the source, but you can blame me for not checking it ;D

Thanks runer, you make me always learn new things!
« Last Edit: September 04, 2012, 12:05:37 pm by MGOS »

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #12 on: September 04, 2012, 12:19:04 pm »
Wow thanks for all the input guys! And yeah, you're right, I meant to do 18 not 16 for the "3" key =P
Also would the arithmetic logic be a good optimization for speed on a ti84+SE?

Offline MGOS

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 336
  • Rating: +95/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #13 on: September 04, 2012, 12:33:49 pm »
Also would the arithmetic logic be a good optimization for speed on a ti84+SE?
For "+" always, but for the multiplying I have to admit that runer's right. Take the bitwise "and" when you compare booleans.


Note:
"2 and 1" would be true in boolean, but you have to use multiplication because the bitwise "and" would return zero.

Offline Derf321

  • LV3 Member (Next: 100)
  • ***
  • Posts: 59
  • Rating: +0/-0
    • View Profile
Re: Enemies Freezing after another enemy is shot? (UPDATED)
« Reply #14 on: September 04, 2012, 04:15:54 pm »
Thank you all! I finally figured out the issue with my program, its that I didn't take into account that I needed to make two separate variables, one for the number of total zombies, and one for the CURRENT number of zombies. It was basically trying to read X/Y/health variables for "dead" zombies, rather than skipping over them, due to the way I set up the memory.

Bottom line, its all solved, thanks to inspiration from you guys! Thanks for the optimization suggestions, i'll definitely use them! Thumbs ups are on me guys ;)