Page 4 of 4

Re: IKD - Atari Combat remake

Posted: Fri Mar 05, 2021 7:41 pm
by D3thAdd3r
I see DrawMap2(-1... which I think will not work the way you want. The map looks 30 tiles wide so use 0 and it will cover the whole screen.

I am only imagining what it's supposed to look like, but 0x25 shows up in the map data at places I would expect a black tile. Looking at tile 0x25, it is not all black so I don't know what the intent is. You may or may not know, but there are no transparent colors on the BG. With tricks you can redraw parts of tiles over sprites for a foreground effect like Alter Ego.

In the loop you clear vram every frame, but you also draw a map the size of the play area each frame. It takes considerable cycles to even clear VRAM, so you definitely want to avoid redundant work. Also, you probably don't even want to draw the map each screen(unless you do destructible tiles, but then you need to draw from ram, only blanking out a tile as it is destroyed).

I can't say exactly why you have the weird issues, but when you run out of cycles weird things can and do happen. You do not need to "clean up" every frame due to sprites either. The kernel interrupts user code(should be WaitVsync(1)) and automatically restores tiles that it out sprites over each frame. However if the kernel doesn't have enough cycles to do this every frame, weird glitches will show up, potential stack trashing, and then all bets are off.

You can save lots of cycle by running a shorter screen.

Re: IKD - Atari Combat remake

Posted: Fri Mar 05, 2021 8:35 pm
by danboid
Thanks for your tips DA!

It was calling ClearVram() every frame that was causing my drawing issues. It's working fine now.

The funky bg colour was intentional, mimicking the original but it is a bit of an eyesore so I think I'm going to just keep it black.

The -1 on the drawmap was an intentional fudge move to make the map fit better but I'm going to unfudge that now.

I expected maps/bgs wouldn't support transparencies.

Re: IKD - Atari Combat remake

Posted: Fri Mar 12, 2021 9:07 am
by danboid
I'm stuck trying to implement collision detection for the walls.

I did try to look at how others had done similar things but the nearest thing I found was over my novice head so I tried to devise my own beginner friendly method but I'm going horribly wrong somewhere.

I have drawn the maze using the DrawMap function and full 8x8 pixel tiles and the map is now drawn in the top left corner of the screen to make any positional calculations easier, using 1 to represent a wall tile and 0 for no wall in the 2D array. The last code I added to the IKD repo was a 2D array of ints to represent a 1 int to 8 pixel scale representation of the maze and I was hoping I could use this for both the tank/wall and bullet/wall collision detection.

In my WIP, non-working code I added a couple of extra variables to the tank struct to store the tanks current location on the map as integers, these indicating which row and column the tank is currently on relating to the 2D maze array maze1map[][]:

Code: Select all

struct tankStruct {
  float x;
  float y;
  int angle;
  int tile_h;
  int tile_v;
Then within the processTank1() function, I have been trying code such as this to try to get the loop to only let the tank move forward if the tank is facing towards a 0 (ie an 'empty' / non-wall) tile in maze1map[][]:

Code: Select all

if ((tank1Held & BTN_UP) && (p1_tank.angle == 4) && (maze1map[p1_tank.tile_h][p1_tank.tile_v + 1] == 0 )) {
            p1_tank.x += p1_bullet.vX / 2;
            MoveSprite(0, p1_tank.x, p1_tank.y, 1, 1);
            p1_tank.tile_v = p1_tank.y / 8;  // Divide the tanks location on screen in pixels (float) 
            p1_tank.tile_h = p1_tank.x / 8; // to work out the players position in the 2D array
Obviously I'd need to write similar code for each of the 16 angles the tank can be facing because it would need to be checking different values in the array but it seems that whereever I stick the code that checks the array value, all hell breaks loose when I try to run it under cuzebox so I presume this code is causing memory corruption somehow.

Could this solution work if implemented correctly or is it fatally flawed somehow?

Re: IKD - Atari Combat remake

Posted: Sun Mar 14, 2021 12:28 pm
by danboid
I'm pretty sure my package from Uze arrived yesterday but I didn't find out until it was too late to go and collect it. I should be able to collect that tomorrow.

Time for a screenshot:
Screenshot at 2021-03-14 11-24-27.png
Screenshot at 2021-03-14 11-24-27.png (28.19 KiB) Viewed 2148 times

Re: IKD - Atari Combat remake

Posted: Tue Mar 16, 2021 4:51 am
by D3thAdd3r
Damn I like how that looks, very classic.

I think your method could work. There are a lot of ways to do collision. If it were me(and this is not a suggestion), I'd drop the floats and used 8.8 fixed point math, with sin/cos tables as values 0-255. Float code is slow and takes lots of code space. It is convenient to use floats and sin/cos without the extra fixed point code though. Probably get things running as is.

To me, I would first determine if the tank is currently inside a wall. If so, move the tank in the opposite direction it is facing and check again next frame. This fixes potential bugs, and would always get a player unstuck if something weird happened.

On frames where the tank is not inside a wall(should be all frames), determine where the new location is and store that. Have a point for top left, top right, bottom left, and bottom right of the new location. Divide these points by 8 to convert to tile coordinates. Maybe just check VRAM like:

//...hit a wall

For projectiles I would do a single point offset from the top left by half the width height(center of mass). You can compare the distance from this point to a point in the middle of a tank. If the distance is smaller than half the width of the projectile and half the width of the tank, there was a hit.

Tanks are slow so they probably can't run through a wall in a single tick. Projectiles might move enough that this check fails to detect a wall. In this case, a projectile move is made of smaller moves. These moves are small enough they cannot pass through a boundary.

Lots of other ways to do it, but bounding circle collision could be the easiest.

Re: IKD - Atari Combat remake

Posted: Tue Mar 23, 2021 10:28 pm
by danboid
Thanks for explaining how you would do this DA.

I'm unsure how vram() works for mode 3. In my projects, the wall tile is tile 37 / 0x25 but I'm confused about RAM_TILES_COUNT. I'm using mode 3 but with no scrolling but I presume, as per your example, I still have to factor in RAM_TILES_COUNT, even though I'm not scrolling just because it is using mode 3?

In my makefile I have -DRAM_TILES_COUNT=23 , so if I was to re-use your example code would it be:

if(vram[(y*VRAM_TILES_H)+x] == 37+RAM_TILES_COUNT)


if(vram[(y*VRAM_TILES_H)+x] == 0x25+RAM_TILES_COUNT)


if(vram[(y*VRAM_TILES_H)+x] == 14+RAM_TILES_COUNT)


if(vram[(y*VRAM_TILES_H)+x] == 0xe+RAM_TILES_COUNT)

The latter two subtracting the 23 RAM tiles first. I had no idea about vram() because it seems to be missing from:

Is there a reason its missing from there?

I had no idea about vram() and RAM_TILES_COUNT until your previous post DA so did I luck out that the tile I'm using for the walls is in position 24+ ie can the first 23 (or whatever RAM_TILES_COUNT is set to) tiles RAM_TILES_COUNT not be used by vram()? Do I have to specify RAM_TILES_COUNT and what are the min/max values that are allowed?

Maybe the answers to these questions could be added to

Re: IKD - Atari Combat remake

Posted: Wed Mar 24, 2021 4:37 am
by D3thAdd3r
There is no vram function, just the array. Scrolling and no scrolling both have ram tiles. From your example, I think you get it. Best way to express it, if I wanted to put a wall tile at (11,22) I could SetTile(11,22,37); Behind the scenes settile() is doing: vram[VRAM_TILES_H*22)+11]=RAM_TILES_COUNT+37; Same thing. You don't need to presubtract anything like your later examples, vram values are just normal numbers for tiles, offset by ram tiles.

So you don't lose the first RAM_TILES_COUNT number of tiles from your tile/BG set. Instead, you lose them at the end. So RAM_TILE_COUNT+0 represents your first flash/BG tile. You can have 256-RAM_TILE_COUNT unique flash/BG tiles due to the 8 bit nature of vram in Mode 3.

Edit- haha I wrote that entry, and judging by humor I might have had one too many drinks. The information there seems basically correct though.

Re: IKD - Atari Combat remake

Posted: Wed Mar 24, 2021 4:58 am
by D3thAdd3r
Ah, so also the subtraction thing is no magic at all if you are thinking of checking against vram for collisions. Your first 2 examples are right. I don't understand the second 2. Did you see indications of a vram function in the link you posted? It was unintentional if so as there isn't one.

Re: IKD - Atari Combat remake

Posted: Sat Apr 24, 2021 7:10 pm
by danboid
Thanks for explaining that DE.

One month later, I finally found the courage to attempt wall tile collision detection (for player one) but I can safely say my first attempt isn't working. See ... #L177-L214

DE did a good job of outlining what needs to be done here but it still wasn't quite enough detail for someone with my level of experience so I found this tutorial useful in explaining how to do basic 2D collision detection / response:

The author of that tutorial is a games dev who prefers to write in C so I emailed him to see if he'd ever heard of the UB. No response yet.

Note that I'm not looking for the cleverest or most efficient way to get this working, just one that works that I can understand so it will probably be the simplest solution or a slightly modified version of my current attempt.

Re: IKD - Atari Combat remake

Posted: Sat May 01, 2021 3:35 am
by D3thAdd3r
So the type of collision response you want will dictate the type of collision detection you need. Without that clearly determined it will be difficult to get a good outcome.

Without the concept of how the tanks will move it would also be hard, but I think you already stated that part if I understand it. You can rotate the tank to any of the fixed angles in a circle, and also drive forward. No other player movement is possible correct?

I watched a video of Combat gameplay to refresh myself, and it seems they use the simplest possible collision. Each game loop, if the player is inside a wall, or they are overlapping the enemy tank, kick them 180 degrees backwards from the direction they are pointing(without changing their actual facing angle), at 2-3 times the maximum tank velocity. If they are not inside a wall or hitting a tank, let them move forward the angle they are facing(collision will be checked next frame). This would have the effect they should get out of a wall(in a possibly weird looking way) should the collision detection have an anomaly which would trap a tank.

I don't think that is the best at all, but is is probably the fastest and easiest possible. All you need is a bounding box overlap test function. The harder/better way is probably trying smaller and smaller velocities until the tank just touches the wall. If this can't be done, start angling the tank parallel to the wall it is hitting(which would have the effect of automatically letting a tank slide through complex areas). This would require knowing which line of the box was hit.

Then also there is player/player and ayer/shot collision. I think player shot collision is pretty obvious, you simply do a bounding box check with the shot and a hit does something. The original Combat seems to treat an enemy tank exactly like a wall. The walls of course could be quickly culled for unnecessary checks since they are aligned on an axis. The player could be close to a wall and actually eject the other player to be stuck in a wall! I think this happens in the original Combat! So the "check if stuck first" element, combined with wrapping to the other side of the screen mechanics, would allow a cheesy way to handle that automatically. To be fair, that stuff is even some of the fun of old games :ugeek: