Jump to content
Retrospect

Fast centipede movement?

Recommended Posts

Hi everyone.  I am working on a possible new game and I wanted the enemies to cascade down the screen with a movement like Centipede.

My idea is, the segments move across the screen and only react to anything that isn't character code 32 - space.  So if it hits the edges of the walls the segment would move down one character and then move the opposite way.

 

So far all my experiments have one thing in common, they're slow.  Even when compiled, specially with player movement and other stuff going on.  Does any of you guys know a routine that would work?  It would be best using characters to get around TI's wonder 5-in-a-line-and-you're-buggered limitation on "hardware sprites".

  • Like 1

Share this post


Link to post
Share on other sites
4 hours ago, Retrospect said:

Hi everyone.  I am working on a possible new game and I wanted the enemies to cascade down the screen with a movement like Centipede.

My idea is, the segments move across the screen and only react to anything that isn't character code 32 - space.  So if it hits the edges of the walls the segment would move down one character and then move the opposite way.

 

So far all my experiments have one thing in common, they're slow.  Even when compiled, specially with player movement and other stuff going on.  Does any of you guys know a routine that would work?  It would be best using characters to get around TI's wonder 5-in-a-line-and-you're-buggered limitation on "hardware sprites".

Could you show us a short video example of what you mean by slow. Not fancy, just one of these things falling down the screen.

And maybe show the mission critical part of the code?

 

I am by no means the expert in these things but I have found that when you need the old 99 to go really fast any extra code in the inner loops has a huge impact.

( found this trying to make code that goes as fast as GCC)

It could be that the normally acceptable overhead of using arrays for example, as we have in BASIC, or even IF ELSE, is just that little extra that is too much for this application.

All that to say you might need a tiny little Assembler routine to push you over the top.

  • Like 1

Share this post


Link to post
Share on other sites

As I've screwed up my code and binned it I can't show it, but I can explain what I've done partly.

I wanted 16 segments of a centipede-like alien (really just 16 aliens travelling together) ... they start at the top left of the screen, they all have arrays for their positions and mode of travel.

DIM AM(16) ! This is Alien Mode , each is set to either 1 or 2 for going left or right
DIM AA(16) ! This is Alien Alive, set to 1 if alien is not dead
DIM AX(16),AY(16) ! Alien's XY coordinates

So the gosub routine was something like this,  there's a variable called "C" to count which alien to move next; and let's say char 128 is the segments. And let's assume that AM(xx) is all set to 1 to start with, moving leftwards .....

4000 C=C+1 
4005 IF C>16 THEN C=1
4010 IF AA(C)=0 THEN 4099
4015 ON AM(C) GOTO 4020,4040

4020 CALL HCHAR(AX(C),AY(C),32) :: AY(C)=AY(C)+1 
4025 IF AY(C)>31 THEN 4030 ELSE 4035
4030 AX(C)=AX(C)+1 :: AY(C)=AY(C)-1 ::CALL HCHAR(AX(C),AY(C),128) ::  AM(C)=2 :: GOTO 4099 ! Sets to mode 2 and return
4035 CALL HCHAR(AX(C),AY(C),128) :: GOTO 4099

4040 CALL HCHAR(AX(C),AY(C),32) :: AY(C)=AY(C)-1
4045 IF AY(C)<2 THEN 4050 ELSE 4055
4050 AX(C)=AX(C)+1 :: AY(C)=AY(C)+1 :: CALL HCHAR(AX(C),AY(C),128) :: AM(C)=1 :: GOTO 4099 ! Sets to mode 1 and return
4055 CALL HCHAR(AX(C),AY(C),128)
 


4099 RETURN

A routine like mine doesn't actually work!  So that's why I need help.  If anyone's done a centipede-like game before please tell me where I've done wrong.  This code is intended to be compiled.  I did get one bit of code something similar to this working but it was far from fast enough.

Edited by Retrospect
  • Like 1

Share this post


Link to post
Share on other sites

I see a little optimizing I would do.  Instead of using 1 and 2 as directional indicators, in my programs I would use -1 and 1, that way just can simply add the direction value to the current location.  To change directions, you simply negate the direction value.

 

I set up 16 aliens with random direction, and X,Y in {1..16},{4..28} then let it rip until a key is pressed.  There is no checking to see if a space is occupied, some aliens will cause others to disappear as they pass each other, or they might over-lap if traveling in the same direction.

 

The speed still is not great but I have not tried compiling.  I have attached a compiled version.

(BTW, there is also no test for going off the bottom of the screen, and doing so in XB256 has some interesting effects.)

 

5 CALL CLEAR
6 RANDOMIZE

10 DIM AM(16),AA(16),AX(16),AY(16)

! SET UP 16 ALIENS WITH RANDOM DIRECTION {-1,1} AND X{1..16),Y{4..28}
20 FOR I=1 TO 16 :: AA(I)=1 :: AM(I)=INT(RND*2)*2-1 :: AX(I)=INT(RND*16)+1 :: AY(I)=INT(RND*25)+4 :: NEXT I

30 GOSUB 4000 :: CALL KEY(0,K,S) :: IF S=0 THEN 30 ELSE STOP

4000 C=C+1+16*(C=16) ! THE MAGIC STARTS HERE
4010 IF AA(C)=0 THEN RETURN
4020 CALL HCHAR(AX(C),AY(C),32):: AY(C)=AY(C)+AM(C)
4025 IF AY(C)>32 OR AY(C)<1 THEN AX(C)=AX(C)+1 :: AY(C)=AY(C)-AM(C):: CALL HCHAR(AX(C),AY(C),30):: AM(C)=-AM(C):: RETURN
4035 CALL HCHAR(AX(C),AY(C),30):: RETURN

(EDIT: Removed the C=1 initialization so alien 1 is not skipped the first time around.)

(I see another optimization I should have made in the bounds checking... but I do not think it will impact speed.)

AL-X

  • Like 2

Share this post


Link to post
Share on other sites

I was wondering how to do binary wrap-around by masking in BASIC. I tried AND. It does not work for the job. 

You have the magic here.   Well done!

4000 C=C+1+16*(C=16) ! THE MAGIC STARTS HERE
  • Like 1

Share this post


Link to post
Share on other sites

Now I want to see how much code that generates since the machine can do it on a register in two instructions.

On a memory location maybe 4 ?

 

 

Share this post


Link to post
Share on other sites
1 minute ago, TheBF said:

Now I want to see how much code that generates since the machine can do it on a register in two instructions.

On a memory location maybe 4 ?

Way bloated compared to Forth or assembly.  The compiled result is around 6k, which includes the XB support routines -- placing characters on the screen, array variables, &c.

Share this post


Link to post
Share on other sites
1 minute ago, OLD CS1 said:

Way bloated compared to Forth or assembly.  The compiled result is around 6k, which includes the XB support routines -- placing characters on the screen, array variables, &c.

That's a nice small runtime block.

I was meaning just the expression you wrote.

 

C=C+1+16*(C=16) 
  • Haha 2

Share this post


Link to post
Share on other sites

thanks guys ... old cs1 i'll try this routine you sent tomorro as i've ended up going out and getting smashed drunk in town, im too far gone to do anything constructive but that code looks good.  i should say tho, the one thing i should have presented was the counter variable C should have started at 16 and counted down to 1 instead of otherway round.

 

i think.

 

 

  • Haha 3

Share this post


Link to post
Share on other sites
25 minutes ago, Retrospect said:

thanks guys ... old cs1 i'll try this routine you sent tomorro as i've ended up going out and getting smashed drunk in town, im too far gone to do anything constructive but that code looks good.  i should say tho, the one thing i should have presented was the counter variable C should have started at 16 and counted down to 1 instead of otherway round.

 

i think.

I am envious.  Still working on house chores.  Maybe a little nip will help with motivation.

 

But, changing the count is easy enough.

C=16

C=C-1-16*(C=1)

 

  • Like 3

Share this post


Link to post
Share on other sites
2 hours ago, Retrospect said:

thanks guys ... old cs1 i'll try this routine you sent tomorro as i've ended up going out and getting smashed drunk in town, im too far gone to do anything constructive but that code looks good.  i should say tho, the one thing i should have presented was the counter variable C should have started at 16 and counted down to 1 instead of otherway round.

 

i think.

 

 

Bodington's or Tetley? :) 

Share this post


Link to post
Share on other sites
6 hours ago, OLD CS1 said:

(I see another optimization I should have made in the bounds checking... but I do not think it will impact speed.)

 

Why not from

4025 IF AY(C)>32 OR AY(C)<1 THEN AX(C)=AX(C)+1 :: AY(C)=AY(C)-AM(C):: CALL HCHAR(AX(C),AY(C),30):: AM(C)=-AM(C):: RETURN

to

4025 IF AY(C)>32 OR AY(C)<1 THEN AX(C)=AX(C)+1 :: AY(C)=AY(C)-AM(C):: AM(C)=-AM(C)

or was that your optimizing thought?

 

...lee

  • Like 2

Share this post


Link to post
Share on other sites
7 hours ago, OLD CS1 said:

4000 C=C+1+16*(C=16) ! THE MAGIC STARTS HERE

 

If C were 0-based, i.e., 0 – 15, the above could be changed to

4000 C = (C+1) AND 15   ! THE MAGIC STARTS HERE

I do not know whether it is faster, but it should work. Of course it would necessitate changes in initialization code to left-shift the arrays indexed with C.

 

...lee

  • Like 3

Share this post


Link to post
Share on other sites
11 hours ago, Lee Stewart said:

 

If C were 0-based, i.e., 0 – 15, the above could be changed to

4000 C = (C+1) AND 15   ! THE MAGIC STARTS HERE

I do not know whether it is faster, but it should work. Of course it would necessitate changes in initialization code to left-shift the arrays indexed with C.

 

...lee

I was thinking the same thing yesterday and  tried a quick test.  It seems I have failed my BASIC test. :(  Too much RPN I guess. 

I suspect the compiler will generate way better code with your expression and using OPTION BASE 0 arrays. 

 

Edit: It occurred to me that @Retrospect might never have encountered this kind of number "wrapping" without using IF THEN so here is some demo code.

 

10 ! binary wrap demo
20 C=(C+1)AND 15
30 PRINT C;
40 GOTO 20

 

  • Like 1

Share this post


Link to post
Share on other sites
11 hours ago, Lee Stewart said:

If C were 0-based, i.e., 0 – 15, the above could be changed to

4000 C = (C+1) AND 15   ! THE MAGIC STARTS HERE

I do not know whether it is faster, but it should work. Of course it would necessitate changes in initialization code to left-shift the arrays indexed with C.

This also works the other way around, since a negative number is all binary ones in the least significant positions.

 

! TRY THIS IN IMMEDIATE MODE

C=15 :: FOR I=1 TO 1000 :: PRINT C :: C=C-1 AND 15 :: NEXT I

Of course, this can only work for and upper value of (2^x)-1, where 0 is in the included set of numbers.  So, {0..3}, {0..7}, {0..15} .. {0,255} ...

 

Many times I wish XB had included the MOD operator.

 

12 hours ago, Lee Stewart said:

or was that your optimizing thought?

Turns out my thought on the additional optimization breaks movement and causes them to run down the screen edge.

 

  • Like 2

Share this post


Link to post
Share on other sites

Here's little centipede movement program I cooked up.  The centipede is defined as three arrays: one for x-coordinate, one for y-coordinate, and one for state.  State can take one of 4 values:

1 = middle part (nothing changes on screen)

2 = tail part (erases current char)

3 = head moving right (moves right or down if blocked)

4 = head moving left (moves left or down if blocked)

 

The trick is that the states rotate through the array - the head and tail states move into to the previous array index "j", which allows the coordinate arrays to remain largely untouched on each step.

100 randomize::call clear::for i=1 to 100::call hchar(rnd*23+1,rnd*31+1,35)::next i
110 call vchar(1,1,35,24)::call vchar(1,32,35,24)
120 dim cx(20),cy(20),cs(20)::for i=1 to 20::cx(i)=2::cy(i)=1::cs(i)=1::next i::cs(1)=2::cs(2)=3::j=20
130 for i=1 to 20::on cs(i) goto 230,220,150,180

140 rem right-moving head  state=3
150 x=cx(i)::y=cy(i)::call hchar(y,x,48)::cs(i)=1::call gchar(y,x+1,c)::if c<>32 then cs(j)=4::goto 200
160 call hchar(y,x+1,62)::cx(j)=x+1::cy(j)=y::cs(j)=3::goto 230

170 rem left-moving head   state=4
180 x=cx(i)::y=cy(i)::call hchar(y,x,48)::cs(i)=1::call gchar(y,x-1,c)::if c<>32 then cs(j)=3::goto 200
190 call hchar(y,x-1,60)::cx(j)=x-1::cy(j)=y::cs(j)=4::goto 230

200 if (y=24) then y=0
201 call hchar(y+1,x,86)::cx(j)=x::cy(j)=y+1::goto 230

210 rem tail state=2
220 call hchar(cy(i),cx(i),32)::cs(j)=2::cs(i)=1
230 j=i::next i::goto 130

This can theoretically handle multiple heads and tails.  If a player bullet hits a centipede part, find the index at that location and change the state to a head, and the next state a tail.

  • Like 7

Share this post


Link to post
Share on other sites
On 12/10/2021 at 7:07 AM, Lee Stewart said:

 

Me, too!

 

...lee

I am right now writing a CALL MOD(number,divisor,result) in RXB 2021

  • Like 2

Share this post


Link to post
Share on other sites
44 minutes ago, RXB said:

I am right now writing a CALL MOD(number,divisor,result) in RXB 2021

Any way to make that a function which can be called in-line with a mathematical formula?

  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, OLD CS1 said:

Any way to make that a function which can be called in-line with a mathematical formula?

I still am stuck trying to figure out how to add tokens to XB, all my attempts have crashed.

  • Sad 1

Share this post


Link to post
Share on other sites
Just now, Retrospect said:

I can so relate to that, but with different things!

Yea was hoping Lee could help me figure out the Assembly ROMs.

  • Like 1

Share this post


Link to post
Share on other sites
23 hours ago, OLD CS1 said:

Any way to make that a function which can be called in-line with a mathematical formula?

Ahh ... if only we had a programmable programming language ...  ;) 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...