﻿ Enemies Freezing after another enemy is shot? (SOLVED)
20 May, 2013, 08:59:31
 OmnomIRC You must Register, be logged in and have at least 40 posts to use this shout-box! If it still doesn't show up afterward, it might be that OmnomIRC is disabled for your group or under maintenance.Note: You can also use an IRC client like mIRC, X-Chat or Mibbit to connect to an EFnet server and #omnimaga.

 Pages: [1]   Go Down
 Author Topic: Enemies Freezing after another enemy is shot? (SOLVED) -  (Read 713 times) 0 Members and 1 Guest are viewing this topic.
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « on: 09 May, 2012, 04:55:35 » 0

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 Hidden:
: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
 ZMBSRC.8xp (5.15 KB - downloaded 16 times.) « Last Edit: 04 September, 2012, 22:17:38 by Derf321 » Logged
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « Reply #1 on: 11 May, 2012, 22:55:21 » 0

 Logged
shmibs
bonsai bok choy wiseguy waterboy
LV10 31337 u53r (Next: 2000)

Offline

Date Registered: 11 June, 2010, 19:36:15
Location: 89B6
Posts: 1840

Total Post Ratings: +227

 « Reply #2 on: 13 May, 2012, 19:41:56 » +1

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:
 12345678910111213141516171819202122232425262728 :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.
 Logged

We're not human, are we?
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « Reply #3 on: 20 May, 2012, 09:10:47 » 0

Days later and I'm still confused by it. I've tried so many things, to no avail :c
 Logged
defmenge
LV3 Member (Next: 100)

Offline

Gender:
Date Registered: 14 February, 2011, 21:10:21
Location: Germany
Posts: 40

Total Post Ratings: +5

 « Reply #4 on: 20 May, 2012, 11:32:54 » +1

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: 20 May, 2012, 11:34:19 by defmenge » Logged

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.
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « Reply #5 on: 21 May, 2012, 22:30:51 » 0

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.
 Logged
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « Reply #6 on: 01 September, 2012, 20:00:25 » 0

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)
MGOS

Offline

Gender:
Date Registered: 29 July, 2011, 16:54:53
Location: Germany
Posts: 295

Total Post Ratings: +73

 « Reply #7 on: 01 September, 2012, 22:11:43 » +2

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.

 123 Lbl DIFF10→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:
 123 0→{L1}L1→{L2}

then, the elses here make absolutely no sense to me:
 12345678910 :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:
 1 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.
 1 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:

 1234 If {L2+(G*4)+2}=1becomesIf {G*4+2+L2}=1

subtracting the value and checking if 0 is more optimized than checking for equality, so:
 1 !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.
 12345678910 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)becomesPxl-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: 04 September, 2012, 18:09:18 by MGOS » Logged

Current
Projects:
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « Reply #8 on: 04 September, 2012, 04:12:47 » 0

.
 123 Lbl DIFF10→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.
 12345678910 :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).
 1 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.
 Logged
MGOS

Offline

Gender:
Date Registered: 29 July, 2011, 16:54:53
Location: Germany
Posts: 295

Total Post Ratings: +73

 « Reply #9 on: 04 September, 2012, 10:25:26 » +2

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:
 1234567 {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 likeA²→Byou 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:
 1 {33,34,26,16,0}→GBD1
at the point where we need the data, we use inData().
 1234 If inData(K,GBD1)→F   ; if the key is one of the weapon selectorsF-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:
 1234 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.

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: 04 September, 2012, 10:28:17 by MGOS » Logged

Current
Projects:
Runer112
LV10 31337 u53r (Next: 2000)

Offline

Gender:
Date Registered: 02 July, 2009, 06:38:05
Posts: 1679

Total Post Ratings: +492

 « Reply #10 on: 04 September, 2012, 17:53:07 » +1

 123 Lbl DIFF10→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:
 123 0→{L1}L1→{L2}

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

then, the elses here make absolutely no sense to me:
 12345678910 :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.
 1 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:
 1234567 {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 likeA²→Byou 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:
 1 {33,34,26,16,0}→GBD1
at the point where we need the data, we use inData().
 1234 If inData(K,GBD1)→F   ; if the key is one of the weapon selectorsF-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:
 1234 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!

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

Offline

Gender:
Date Registered: 29 July, 2011, 16:54:53
Location: Germany
Posts: 295

Total Post Ratings: +73

 « Reply #11 on: 04 September, 2012, 18:03:19 » +1

Only applies if the pointer is not a constant! 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

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

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

Current
Projects:
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « Reply #12 on: 04 September, 2012, 18:19:04 » 0

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?
 Logged
MGOS

Offline

Gender:
Date Registered: 29 July, 2011, 16:54:53
Location: Germany
Posts: 295

Total Post Ratings: +73

 « Reply #13 on: 04 September, 2012, 18:33:49 » +1

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.
 Logged

Current
Projects:
Derf321
LV3 Member (Next: 100)

Offline

Last Login: 10 May, 2013, 18:34:42
Date Registered: 02 December, 2011, 05:55:26
Posts: 58

Topic starter
Total Post Ratings: 0

 « Reply #14 on: 04 September, 2012, 22:15:54 » 0

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
 Logged
 Pages: [1]   Go Up