It is currently Thu May 23, 2019 1:48 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Sat Dec 22, 2018 11:25 pm 
Offline

Joined: Tue Dec 11, 2018 9:47 am
Posts: 8
As a learning exercise I'm trying to make a Tetris clone. I had been going through some tutorials that got me as far as drawing background, sprites, and taking controller input. I applied this info in making a background to show the play area. Due to the limitations of number of onscreen sprites, my assumption of how Tetris works is there are 4 sprites representing the piece that is currently in play. Once the piece lands into its final position, I am assuming that piece then becomes part of the background, and the next piece in play gets some new sprites to represent it. Subsequent pieces in play need to stay within the boundaries of the play area, and they cannot encroach on any of the previous blocks in the play area.

Right now I've hooked up left and right controller input. I set it up so that the piece can move left or right, but must stay within the boundaries of the play area. I have a file to represent the background - I've manually placed a couple of blocks in the play area so that I can experiment with new logic to prevent the piece in play from encroaching into those blocks.

Here is a snippet of what is in my background data. Bytes beginning with a 1 like $1C and $19 are using tiles that represent outside the play area. Values of $00 are blank and are empty spaces within the play area. Bytes that begin with 0 like $0C and $0A represent spaces in the playing area that are occupied with blocks.
Code:
.db $1B,$1E,$16,$17,$19,$13,$1C,$19,$1D,$17,$16,$17,$19,$17,$16,$1D
  .db $1B,$1A,$19,$1D,$17,$16,$18,$1E,$1A,$1C,$16,$18,$15,$18,$1E,$19

  .db $1B,$16,$1B,$19,$18,$1A,$1E,$19,$12,$1B,$1C,$1C,$0C,$00,$00,$00
  .db $00,$00,$00,$00,$0A,$0A,$1A,$1A,$15,$17,$1C,$1A,$16,$17,$1A,$1C

  .db $19,$12,$1B,$1C,$16,$1B,$16,$1B,$1A,$15,$17,$1E,$0C,$00,$00,$00
  .db $00,$00,$0C,$0C,$00,$0A,$19,$18,$1A,$19,$14,$1B,$15,$1B,$15,$17


I define these variables in the zero page since I think I'll need indirect indexed addressing to read what's in my background data.
Code:
;i attempt to use these bytes for indirect indexed addressing of background data
gridLocationLowByte .rs 1
gridLocationHighByte .rs 1


I believe what I need to do is to always know the current location of the 4 squares that represent the playing piece relative to the background tiles that they cover. If the background is a 960 byte array, I believe the initial position that I'm placing my pieces are at these positions. I'm hard coding the starting position here. Additionally I'll need to know the destination position when the player tries to move a piece in order to determine whether the desired move is legal or not.
Code:
playerGridPos1 = $D1
playerGridPos2 = $D2
playerGridPos3 = $D3
playerGridPos4 = $F1

playerNextGridPos1 .rs 1
playerNextGridPos2 .rs 1
playerNextGridPos3 .rs 1
playerNextGridPos4 .rs 1


I have this code to check to see if my move is legal or not. The first piece section is checking to see if the adjacent left square is still within the boundaries of the play area. I could remove this code if I'm instead able to see if the adjacent square's using empty background tile $00.
Code:
MoveLeftIfLegal:
; check if square 1 new position is within play area
  LDA playerSquare1x
  SEC
  SBC #$08
  CMP #playAreaLeftBoundary
  BCC DontMoveLeft
  STA playerNextPos1x


This is the part that has problems. I'm trying to figure out what background tile exists in the left adjacent square. I believe I should be able to read and write to the background data that I used to draw the background. Right now I'm not getting the expected results. I'm not sure if I'm using the wrong initial position for my pieces, if I'm doing the indirect indexed addressing wrong, or if there's just something fundamentally wrong with my approach.

This code first attempts to subtract 1 from the current position of the leftmost sprite and saves it in playerNextGridPos1. I next attempt to use indirect indexed addressing to figure out what tile occupies the same square of playerNextGridPos1 in the background by using playerNextGridPos1 as the offset. I know that playerNextGridPos1 may be more than 255 bytes away from the first byte of my background data which is why I increment gridLocationHighByte if carry flag is true.

Code:
  LDA playerGridPos1
  SBC #$01
  STA playerNextGridPos1

; check if square 1 new position is not occupied
  LDA #LOW(background)
  STA gridLocationLowByte
  LDA #HIGH(background)
  STA gridLocationHighByte

  LDA gridLocationLowByte
  ADC #playerNextGridPos1
  BCC BlockOneNotCrossedPage
  INC gridLocationHighByte
BlockOneNotCrossedPage:
  LDY #playerNextGridPos1
  LDA [gridLocationLowByte], y
  CMP $00
  BNE DontMoveLeft


I believe the background data occupies 960 bytes starting at $E000. Initial value of playerGridPos1 is $D1, which I hardcoded because I believe the sprite I'm interested in begins on top of the tile specified in the position D1 of my background array, $E0D1. When I move left, I expect the block to move to $D0, which is stored in playerNextGridPos1. I believe gridLocationLowByte holds the value 00 and gridLocationHighByte holds the position of E0. When I add gridLocationLowByte and playerNextGridPos1, I believe carry flag would not be set so gridLocationHighByte should not be incremented since I'm still in the first 255 bytes of the background data. I'm expecting LDA [gridLocationLowByte], y to give return me a value of #$00, representing an empty space in the play area. However I don't believe this is returning #$00.

my project can be found here:
https://github.com/buschi8282/falling-blocks


Top
 Profile  
 
PostPosted: Sun Dec 23, 2018 10:16 am 
Online
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2507
Location: DIGDUG
I'm assuming that your bg array, each byte represents a 8x8 pixel area of the screen. So you should be dividing the player pieces x and y by 8 each (after you adjust their offsets to align to the board).

You can do a quick divide by 8 like

lsr a
lsr a
lsr a

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Mon Dec 24, 2018 8:21 pm 
Offline

Joined: Tue Dec 11, 2018 9:47 am
Posts: 8
Thanks for the tip Doug, that seems to be a useful trick. I'm not sure I really understand how exactly this would be applied though. If you can provide some additional details about how it would be used it could help me better understand.

I've made some progress - I can now read the contents of the background array for adjacent squares and can prevent the piece in play from moving over the adjacent squares. Only left and right movement is so far supported, I need to add support for downward motion, I also need to add more logic to handle different shape pieces as well as to make sure I'm checking all the necessary adjacent squares.

The code from my previous example had a few bugs. I now keep track of player's grid position using two bytes, the location of which get set in the game loop. Original implementation had them hardcoded to a specific value. It looks like when I was setting initial value instead of just reserving memory I was getting unexpected results. The other bug was I was not correctly clearing or setting the carry flag before doing addition or subtraction. I had assumed this was only important if you weren't overflowing the value for 1 byte values but this is not the case. Here are some examples of my current implementation:

high and low bytes for keeping track of player's current position, as well as temporary storage to keep track of player's next location
Code:
playerGridPos1 .rs 1
playerGridPos1_hb .rs 1

playerNextGridPos1 .rs 1
playerNextGridPos1_hb .rs 1


The game loop sets initial position for the rightmost square. I'll need to replace this with whatever logic will be used to give a player a new piece during the game.
Code:
  LDA #$CF
  STA playerGridPos1
  LDA #$00
  STA playerGridPos1_hb

GameLoop:
  JMP GameLoop



This is logic used when player attempts to move the piece left:
Code:
  LDA playerGridPos1
  SEC
  SBC #$01
  STA playerNextGridPos1

  LDA #LOW(background)
  STA gridLocationLowByte
  LDA #HIGH(background)
  STA gridLocationHighByte
  LDY playerNextGridPos1
  LDA [gridLocationLowByte], y
  CMP $00
  BNE DontMoveLeft


This seems to work - I need to incorporate some additional logic to work with the high byte. Without this I think there could be some edge cases that would break if I'm moving from location $0100 to $00FF and similar things like that. I've got some high byte stuff implemented for right movement that I need to apply here.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group