Subject: Conditional loop

From: Owen Brand <[email-masked]>
Date: Sun, 14 Feb 2010 11:22:43 -0500

Trying to implement a "conditional loop" in the game here, and running  
against a bit of an issue.

Goal---

1) "Draw one token on the screen, create a CALL COINC(#1,64,32) (to  
coincide with the drawn token)"
2) "When the token is collided with by SPRITE #1, erase said token,  
and draw another one with a new coinciding CALL COINC elsewhere on the  
screen"
3) Repeat process 5 times

One formula I had was something like this:

290 TOY=32 :: TOX=40 :: TGET=0
300 DISPLAY AT (TOY/8,TOX/8):token
301 CALL COINC(#1,TOY,TOX,A)
302 IF A>0 THEN GOTO 1000

<<rest of bonus stage loop>>

1000 CALL SOUND(happy sound):: DISPLAY AT(TOY/8,TOX/8):" "
1001 SCO=SCO+100
1002 TGET=TGET+1 :: IF TGET=5 THEN GOTO beginning of main screen
1003 TOY=TOY+32 :: TOX=TOX+40
1004 GOTO 300

This should, theoretically, set the variables, display at(4,5) a  
token--- set up a call coinc for that spot on the screen and then  
execute program--- if the player hits that spot, it should play a  
happy sound, add 100 to SCO which is points, add 32 and 40 to the Y  
and X positions respectively, add 1 to the variable TGET (indicates  
how many tokens have been gotten) and then repeat--- if TGET is 5,  
then end the bonus level, and return to main gameplay screen....

Is this efficient?  I just threw this together as I was thinking about  
it a few minutes ago... Is there a better way to achieve this goal, or  
am I on the right track?

Owen Brand
Opry99er.com

---

From: Marc Hull <[email-masked]>
Date: Sun, 14 Feb 2010 09:51:28 -0800 (PST)

your mixing your graphics I coordinates with your sprite coordinates and IIRC don't you need a tolerance as well as a return variable ?

--- On Sun, 2/14/10, Owen Brand <[email-masked]> wrote:

From: Owen Brand <[email-masked]>
Subject: [TI994A] Conditional loop
To: "[email-masked]" <[email-masked]>
Date: Sunday, February 14, 2010, 10:22 AM

  

Goal---

1) "Draw one token on the screen, create a CALL COINC(#1,64, 32) (to  

screen"

300 DISPLAY AT (TOY/8,TOX/8) :token

301 CALL COINC(#1,TOY, TOX,A)

1000 CALL SOUND(happy sound):: DISPLAY AT(TOY/8,TOX/ 8):" "

1001 SCO=SCO+100

1004 GOTO 300

am I on the right track?

Owen Brand

Opry99er.com

---

From: Marc Hull <[email-masked]>
Date: Sun, 14 Feb 2010 09:52:57 -0800 (PST)

Sorry should have read your code closer.....

 

    

Goal---

screen"

1001 SCO=SCO+100

1004 GOTO 300

am I on the right track?

Owen Brand

Opry99er.com

---

From: mark wills <[email-masked]>
Date: Sun, 14 Feb 2010 10:15:12 -0800 (PST)

Pre compute your token locations in an array at the start of your level, before the action starts.

DIM TOKEN(10) ! SPACE FOR 5 TOKENS
FOR I=1 TO 10 STEP 2
TOKEN(I)=INT(RND*10)+1   ! RANDOM Y
TOKEN(I+1)=INT(RND*31)+1 ! RANDOM X
NEXT I

Now, before the action starts, initialise a token counter, and point to the first token:

TC=1 ! token counter

Just before the action loop, display your token:
TY=TOKEN(TC)
TX=TOKEN(TC+1)
CALL HCHAR(TY,TX,42)

In your loop, have your COINC checking the token Y & X
CALL COINC(#1,TY,TX)

When you detect a hit, erase the token, advance the token counter, and draw a new token:

CALL HCHAR(TY,TX,32)
TC=TC+2
TY=TOKEN(TC)
TX=TOKEN(TC+1)
CALL HCHAR(TY,TX,42)

Voila ;-)

M

>Sent: Sun, 14 February, 2010 16:22:43

---

From: "Dan O'Quinn" <[email-masked]>
Date: Sun, 14 Feb 2010 13:50:44 -0500

http://cgi.ebay.com/TI-99-4a-CompactFlash-Drive-PIO-Port_W0QQitemZ200439167063
TI-99/4a CompactFlash Drive/PIO Port

---

From: Owen Brand <[email-masked]>
Date: Sun, 14 Feb 2010 14:22:02 -0500

Thanks Mark.  As the token is actually 4 characters in size, the  
drawing and erasing are a tad more complex than my sample code--- but  
a simple SEG$ function makes it easy to draw, and a short CALL HCHAR 
(TOY/8,TOX/8,32,2):: CALL HCHAR(TOY/8+1,TOY/8,32,2) makes it pretty  
easy to do both... I love the idea behind setting Tokens up to  
randomly display is a good idea---- that or pre-setting them  
manually.... Rather than setting them up to generate on an increasing  
grade--- I'll investigate this more.  Thanks for the suggestion!

Owen Brand
Opry99er.com

---

From: "Matthew" <[email-masked]>
Date: Sun, 14 Feb 2010 19:24:34 -0000

Hey Owen.  A couple of things jump out at me when I read that code.  

First is the (TOY/8,TOX/8) that happens twice.  On the TI, DIV (divide) is the *slowest* instruction on the CPU and is generally avoided at all costs.  If you were working in assembly you would use a SRA (shift right arithmetic) or SRL (shift right logical) to do the division, but unfortunately in BASIC you don't have access to the shift instructions, so you can only be aware that any divide is going to slow you down by a big factor  Also, all numeric variables in BASIC are stored in TI's floating point format, which is insane IMHO.

Second, try to avoid the GOTO statement as much as possible.  BASIC is usually condemned for this reason alone because the random jumps all over the place make the code very hard to follow.  Try to code as if you didn't have line numbers, which I know you can do in BASIC, but look at them as labels.

Some pseudo code might be (assumes all variables are global like in BASIC):

while ( game running )

  ...

  if ( time for bonus round )
    bonus_round()

  ...

wend

procedure bonus_round()

  set up variables

  while ( rounds > 0 and timer > 0 )

    if ( sprint hit token )
      do_bonus_hit()

    timer--

  wend

end proc

procedure do_bonus_hit()

   play sound
   make new token location
   draw new token
   update score
   update rounds

end proc

Although BASIC does not have a while/wend construct, you can simulate it.  Also, BASIC does not have "procedures" or "functions", it does have GOSUB which works almost the same way (and I can't remember if GOSUB can be nested?)

Here is some code you might mess with.  Some notes:

* The targets of the GOTO and GOSUB calls are REM statements that indicate what is happening at that line.  Basically these are our way of making "labels" in a BASIC program and the way we simulate block constructs found in other languages.

* Use HCHAR instead of DISPLAY AT for single or repeating characters, it is faster.  DISPLAY AT has a lot of overhead that you just don't need when putting a single character on the screen.

* I added variables to track the sprite coordinates (SPRX and SPRY) separately and derive them from the token location by multiplying by 8.  The multiplication is faster than the divide and the calculation is performed outside of any loops.

* I added a timer for the bonus round.  Seems like there should be some time limit, but you can remove it if it does not make sense.  The starting time for the timer is arbitrary and you will have to experiment with values to get the timing right.

* Without the timer, your COINC call could be much tighter, which would probably work better in BASIC.  Lines 1120 to 1140 would change to:
  1120   CALL COINC(#1,SPRY,SPRX,8,A)
  1130   IF A = 0 THEN 1120
  1140   GOSUB 1300

* In the bonus round subroutine, the erasing of the old token and displaying of the new token happen as close together as possible so there is minimal time when a token is not shown on the screen.  In this case, only the calculation of the new token location is between erasing and drawing.

* I used spaces to show indentation an help identify blocks in the code, unfortunately BASIC will suck these out of your program if you try to include them.

Well, I hope some of this helps.

Matthew

100 REM main screen

some other code

1000 REM set up for bonus round
1010 TOKX=5 :: TOKY=4
1020 SPRX=TOKX*8 :: SPRY=TOKY*8
1030 ROUNDS=5 :: TIMER=2000
1040 CALL HCHAR(TOKY,TOKX,TOKEN)

1100 REM while rounds > 0 and timer > 0
1110 IF ROUNDS < 1 OR TIMER < 1 THEN 1200

1120   CALL COINC(#1,SPRY,SPRX,8,A)
1130   IF A <> 0 THEN GOSUB 1300
1140   TIMER=TIMER-1

1190   GOTO 1100
1200 REM wend
1210 GOTO 100

1300 REM bonus round got token
1310   CALL SOUND(happy sound)
1320   SCO=SCO+100
1330   ROUNDS=ROUNDS-1
1350   CALL HCHAR(TOKY,TOKX,32)
1360   TOKX=TOKX+5 :: TOKY=TOKY+4
1370   CALL HCHAR(TOKY,TOKX,TOKEN)
1340   SPRX=TOKX*8 :: SPRY=TOKY*8
1390 RETURN

---

From: Keith Bergman <[email-masked]>
Date: Sun, 14 Feb 2010 14:44:35 -0500

Matthew,

Great stuff in this email.  Printing and saving it for further study.
Thanks!

Keith

On Sun, Feb 14, 2010 at 2:24 PM, Matthew <[email-masked]> wrote:

> First is the (TOY/8,TOX/8) that happens twice. On the TI, DIV (divide) is
> the *slowest* instruction on the CPU and is generally avoided at all costs.
> If you were working in assembly you would use a SRA (shift right arithmetic)
> or SRL (shift right logical) to do the division, but unfortunately in BASIC
> you don't have access to the shift instructions, so you can only be aware
> that any divide is going to slow you down by a big factor Also, all numeric
> variables in BASIC are stored in TI's floating point format, which is insane
> IMHO.
>
> Second, try to avoid the GOTO statement as much as possible. BASIC is
> usually condemned for this reason alone because the random jumps all over
> the place make the code very hard to follow. Try to code as if you didn't
> have line numbers, which I know you can do in BASIC, but look at them as
> labels.
>
> Although BASIC does not have a while/wend construct, you can simulate it.
> Also, BASIC does not have "procedures" or "functions", it does have GOSUB
> which works almost the same way (and I can't remember if GOSUB can be
> nested?)
>
> * The targets of the GOTO and GOSUB calls are REM statements that indicate
> what is happening at that line. Basically these are our way of making
> "labels" in a BASIC program and the way we simulate block constructs found
> in other languages.
>
> * Use HCHAR instead of DISPLAY AT for single or repeating characters, it is
> faster. DISPLAY AT has a lot of overhead that you just don't need when
> putting a single character on the screen.
>
> * I added variables to track the sprite coordinates (SPRX and SPRY)
> separately and derive them from the token location by multiplying by 8. The
> multiplication is faster than the divide and the calculation is performed
> outside of any loops.
>
> * I added a timer for the bonus round. Seems like there should be some time
> limit, but you can remove it if it does not make sense. The starting time
> for the timer is arbitrary and you will have to experiment with values to
> get the timing right.
>
> * Without the timer, your COINC call could be much tighter, which would
> probably work better in BASIC. Lines 1120 to 1140 would change to:
> * In the bonus round subroutine, the erasing of the old token and
> displaying of the new token happen as close together as possible so there is
> minimal time when a token is not shown on the screen. In this case, only the
> calculation of the new token location is between erasing and drawing.
>
> * I used spaces to show indentation an help identify blocks in the code,
> unfortunately BASIC will suck these out of your program if you try to
> include them.
>
> --- In [email-masked] <TI994A%40yahoogroups.com>, Owen Brand
> <owenbrand@...> wrote:
> >

---

From: Owen Brand <[email-masked]>
Date: Sun, 14 Feb 2010 14:47:13 -0500

That's all great stuff Matthew, thank you.  Yea, XB is slow as hell---  
but for this particular game, it will suffice.  What I didn't include  
in my sample code was everything else that is going on.  There are 9  
UFOs flying at varying speeds across the screen from right to left...  
The goal is to collect all the tokens without getting "abducted".  :).  
Anyway, each time you retrieve a token, the speed of the UFOs  
increasees, making it more difficult to get to the next one  
unscathed.  That's really the goal--- and this is just the bonus  
round.  :). So, the timer, while a fantastic idea, won't be needed  
here.  The SPRITE collision detect is a variant of CALL COINC(ALL,C)  
and it just checks for the collision between the play piece and the  
enemy SPRITEs.  This is becoming a very interesting program with all  
the marvellous suggestions. I will keep in mind your suggestion on  
avoiding DIV.  Thanks alot man.  :).

Owen Brand
Opry99er.com

On Feb 14, 2010, at 2:24 PM, "Matthew" <[email-masked]> wrote:

> First is the (TOY/8,TOX/8) that happens twice. On the TI, DIV  
> (divide) is the *slowest* instruction on the CPU and is generally  
> avoided at all costs. If you were working in assembly you would use  
> a SRA (shift right arithmetic) or SRL (shift right logical) to do  
> the division, but unfortunately in BASIC you don't have access to  
> the shift instructions, so you can only be aware that any divide is  
> going to slow you down by a big factor Also, all numeric variables  
> in BASIC are stored in TI's floating point format, which is insane  
> IMHO.
>
> Second, try to avoid the GOTO statement as much as possible. BASIC  
> is usually condemned for this reason alone because the random jumps  
> all over the place make the code very hard to follow. Try to code as  
> if you didn't have line numbers, which I know you can do in BASIC,  
> but look at them as labels.
>
> Although BASIC does not have a while/wend construct, you can  
> simulate it.  Also, BASIC does not have "procedures" or "functions",  
> it does have GOSUB which works almost the same way (and I can't  
> remember if GOSUB can be nested?)
>
> * The targets of the GOTO and GOSUB calls are REM statements that  
> indicate what is happening at that line. Basically these are our way  
> of making "labels" in a BASIC program and the way we simulate block  
> constructs found in other languages.
>
> * Use HCHAR instead of DISPLAY AT for single or repeating  
> characters, it is faster. DISPLAY AT has a lot of overhead that you  
> just don't need when putting a single character on the screen.
>
> separately and derive them from the token location by multiplying by  
> 8. The multiplication is faster than the divide and the calculation  
> is performed outside of any loops.
>
> * I added a timer for the bonus round. Seems like there should be  
> some time limit, but you can remove it if it does not make sense.  
> The starting time for the timer is arbitrary and you will have to  
> experiment with values to get the timing right.
>
> * Without the timer, your COINC call could be much tighter, which  
> would probably work better in BASIC. Lines 1120 to 1140 would change  
> to:
> displaying of the new token happen as close together as possible so  
> there is minimal time when a token is not shown on the screen. In  
> this case, only the calculation of the new token location is between  
> erasing and drawing.
>
> * I used spaces to show indentation an help identify blocks in the  
> code, unfortunately BASIC will suck these out of your program if you  
> try to include them.
>

---

From: mark wills <[email-masked]>
Date: Sun, 14 Feb 2010 20:47:46 -0800 (PST)

Good avice Matthew.

I'm a HUGE advocate of SUBs in XB. They make the code modular, and easy to follow. You get local variables, and can actually get a very nice structured program developed.

YOu can design top-down, and no need to worry about line numbers, since you refer to your code with names. Thus if you change line numbers/re-factor, it doesn't matter...

M

>
>From: Matthew <[email-masked]>
>To: [email-masked]
>Sent: Sun, 14 February, 2010 20:24:34
>Subject: [TI994A] Re: Conditional loop
>
> >
>
>
>
>
>  >
>>      
> 
>>    bonus_round( )
>>procedure bonus_round( )
>>      do_bonus_hit( )
>>procedure do_bonus_hit( )
>
>>play sound
>>   make new token location
>>   draw new token
>>   update score
>>   update rounds
>
>>end proc
>
>>  1120   CALL COINC(#1,SPRY, SPRX,8,A)
>>  1130   IF A = 0 THEN 1120
>>  1140   GOSUB 1300
>
>>1040 CALL HCHAR(TOKY,TOKX, TOKEN)
>
>>1120   CALL COINC(#1,SPRY, SPRX,8,A)
>>1140   TIMER=TIMER- 1
>>1330   ROUNDS=ROUNDS- 1
>>1350   CALL HCHAR(TOKY,TOKX, 32)
>>1370   CALL HCHAR(TOKY,TOKX, TOKEN)
>>--- In TI994A@yahoogroups. com, Owen Brand <owenbrand@. ..> wrote:
>>>