Zerberk is a game I tried to finish in January, 2009. I got about 40% into it or so. At one point, I almost thought that I would finish.
What's left is implementing the different enemies, do the level design and progress control, and I need to do some arcade cabinet style art. There's no player in the game yet, but the enemies (all entities in fact) are already controlled by the AI using dual analog joypad input (a virtual joystick), and teams are supported. The enemies fight little wars against each other, with me studying them to find bugs. Writing the joypad calibration and mapping thing is so boring I'll probably do it last. I can live without it now anyways.
The text here is taken from forum posts and is unedited. Disjointedness might be felt. The game design changed as I progressed. Well, I didn't actually progress much, since I came up with more stuff to do the further I got. At any rate, I embrace feature creeping, even if it means not finishing. I wouldn't want to play a simple finishable game anyways.
I made New year's resolution to at least finish one project this year, and if I can do that I'll go for 3. So, I thought I start with something relatively simple. I've already feature creeped it, but it's still doable, I think. One step at a time. If I just work on it every now and then and make progress, it will get finished. It really shouldn't be more than 3 days for a working prototype and that *pi for polish.
So, I picked Berzerk with a touch of Robotron.
Here's a mock up I made a year ago. I don't think it's particularly exciting as a game project, other than the possibility I have to put bots on the player's side (team lists) and do a few things with the AI. It's basically Berzerk with a lot larger playfield, more enemies, more AI, more bullets, kinda Robotron tempo. Walls will be destructible. The goal is to touch the corner stuff and then exit to the next level. Perhaps for lives I'll use an emergency teleport device with a set number of charges. The player simply spawns in a new maze. I'm not sure if I want to respawn the player in the same maze.
There'll be a border with arcade cabinet art and a digital score counter, kind of like pinball. Perhaps a money slot with buttons for starting games and such.
Controls, I don't know. Joypads could work, but then I need to write calibration UI crap. Mouse is simple but what about multiplayer then? I don't want to do 4 or 8 way controls. I need to buy a new Joypad anyways, dual analog.
I won't list what to do, because I can't handle ToDo lists well it seems, but here's what's done:
Pixel graphics and mock up.
Map class can generate mazes based on certain parameters. I wrote mot of this code in one go, and it just ran and did its stuff. It's always surprising when that happens.
Map class can do a Line of Sight check.
Map class is somewhat proper OOP and the dimensions of various things aren't hardcoded.
Well, it's Day 2 and I'm still working. Usually I have 1.5 weeks for art projects, but programming stuff, I rarely survive even a few days.
Loading tiles graphics for the map, although there's no way to damage the walls yet, so they're all in the intact state.
Pads class is halfway in. They just don't check against any actors yet.
Simple play class manages the play state of the program. Found a similar project of mine I'll be able to copy paste some code from.
Everything is flat white then colored ingame, allowing me to flash colors, etc.
Using constants allowing me to set scale and position of stuff. Right now each cell is 1.0 units for physics, 4 pixels at 2x for drawing, and the map is slightly offset so I get borders.
Main class managing program flow and boot up of all other classes.
Some timers for blinking / frame loops, and frame measure. 3ms is a bit slow but the map is 97*97 cells. I only draw the wall tiles of course, but each of those are scaled 2x in realtime. they should be pre-scaled, but it's all GPU thread anyways so it doesn't show up in the ms timer. I'm guessing it's going through 9409 cells that is slow.
Disabled subpixel font smoothing in Mac OS so now my 'standing' 22" widescreen (good for text editing) can show crisp text. Apparently there's some app which allows you to use different settings for your monitors, but it doesn't matter a lot.
Oaaugh! Getting heavy to row now, this boat.
Type TEntity Abstract ------------------ A Type is a Class in BlitzMax. Entities are my most basic particle.
Type TBlip Extends TEntity Abstract -- Containing most of the meat, but needs a lot more work. Contains Functions and Methods for colliding and moving actors around, and also all Lists for Updating.
Type THulk Extends TBlip Final -------- A basic enemy.
Type THulkBullet Extends TBlip Final
Made graphics for 7 types of Blips which now loads. They animate properly and can damage blink.
Edge walls are invulnerable so they're acting as 'sentinels'. I might be able to avoid frequent coordinate bounds checks.
I have some old code from my robotron project. Its structure is sound, but converting it is a lot of job. It has some nice features which I worked out back then. I have side (good/evil) lists, and all 'blips' can be controlled by either a joystick or a virtual 'AI joystick'.
I just put some enemies on different sides, and made them have a little shootout. Still, a lot of work left. They won't collide with the maze (although their bullets will). I need to rewrite the blip-blip collision code so the map 'buckets' are used. This means that the blips are actually just 1.0 units big since they can't be larger than their buckets. Meaning, They'll stack tight like StarCraft tanks if the graphic is big. Of course, I can increase the size of their hitbox by adding in the bullet size, which is 0.5 to 1.0 units big too.
I'll do the Arcade cabinet border to spice things up art-wise.
AI's now have to swing their aims with a mass, causing them to oscillate a bit (with random force added to the aim change). It's a more human way to handle AI aim since they will settle on a target which stands (relatively) still.
Made better cracked walls.
No screen though, it's bedtime.
Later, The AI will scan for actors not on their side and mark the spot of their target rather than the target itself. Then fire at that spot, also trying to reach it for a while. This will mean that they'll be able to pursue targets to some extent. If a target goes out of sight they still have the spot. I don't have a pathfind planned though. Not sure about 'leading' for AI shooting, I can't code that properly... although I think I did once for a quake mod.
I'll try to do mental states for the AI, meaning, a bot will have a momentum when moving between mental states. If it's patroling it's not very alert, and it'll take a while for it to target (i.e. it won't snipe you in the face the same millisec you stick your face around the corner). Also once it is firing at a spot, it'll go trigger happy and keep firing at that spot for a while.
Not sure if I should show the aim of the bots. Maybe a laser sight dot. Ambusing them from the back would work, cuz it takes a while for them to swing around the aim. I need to add a safety so they will only fire when the aim is within a certain threshold. Right now they just spray wildly before settling.
Test level can be reset quickly. (All classes can reset their stuff)
Cleaned up some of that old Blip code, made it more consistent.
Implemented much of the AI, which I wrote all in one go and it just worked... probably 1-2hrs of code. Except it didn't work because I had to force a float into an int at one place... took 30 mins to hunt down that one. But then it worked! Got 9 mental states now. Would be cute to make little icons for them, like a ! over the head.
Still some bugs to hunt down. My sentinels didn't catch one bullet, I think due to some overflow causing a bullet to go to crazy coordinates. I put a bug-catcher in place, and it hasn't reacted since. I hate when bugs are just rare and seemingly spontaneous. Computers are supposed to be deterministic!
Now I need to rewrite all collision code cuz I scrapped the old one. I need to write Actor-Tile and Actor-Actor collision code, using the Bucket 3*3 checks thing. It'll speed up the code a lot since there's only 9 cells to check, not the entire list of everything.
Bullets... at first I planned to make it so they could collide with everything, including other bullets, but putting them in the buckets... will make things too crowded and they'll obscure LoS (...unless I make another dimension for the bullets). I'll just avoid putting bullets in the buckets, but check the bucket at a bullet's coords for anything the bullet can collide with. Hmm, yes, we'll see.
Got the aim swinging method to work properly. Now they only shoot if their aim is within 20 degrees. I'm using a velocity vector (based on angle difference between actual aim and ideal aim) and friction. Plotting those now for debug purposes (magenta and green dots). You can see a trace line being performed (dark gray).
Oh, yes, I implemented sounds a while ago. Using SFXR (?) files I had laying around.
Put my 9 colors (BGW,RGB,CMY) into a TPalette class and made constants so I can set certain colors easily. Idea now: Make color flash lists for the palette class so I can have some sexy Robotron flashing. Done.
Buckets are finally used. Gray squares here is actors that should be bump-tested. Red is someone being prevented from moving into someone else's bucket.
Bumping (disabled on this screen) will bump actors away from each other (probably before they even get close to moving into someone else's bucket.)
Now I have Actor to Tile collisions to do. It will be tricky, since I might want to allow gliding against walls. I can't just halt the actor. So I need to do the 4 corner thing it seems.
Sentinels! Neighbour checks forced me to deploy more sentinels around the map. Three thick just to be on the safe side, but I can set any thickness with a constant. CPU is more expensive than some kb of memory and I'd rather skip messy bounds checks in the code.
Bullet to Actor collisions are back in and now my bots are dying like flies. Bullets don't stay in buckets, but they check neighbours for their prey.
Wall hit sound.
Because Actors now exist in buckets, they obscure LoS just as walls do. Friendlies can still end up in the line of fire though:
The bots are lousy at aiming and often take chances, because I made them that way.
The LoS code doesn't care where in the bucket the Actor is, so an Actor can be at an edge to an empty bucket and not be noticed.
Seems my biggest slowdown now is drawing the map. I could save processing power by keeping the map as an image which I modify parts of if there's any changes to walls (being destroyed).
It seems that I can not modify Images in the GPU memory.
But I can modify Pixmaps in the regular memory handled by the CPU.
Pixmaps have to be transferred over the bus to the GPU to be drawn. Slow.
There might not be a way to Draw an image/pixmap onto another image/pixmap.
Perhaps I can
If any changes to map
? Draw the map image onto the back buffer
? Draw the modified tiles (How do I know which though? Make a list?)
? ReDraw the map tile by tile (all 9k of them).
GrabImage - I suppose it is transferred into the GPU, replacing the old one with that handle. GrabImage doesn't take width or height so I suppose it's at a fixed place in the GPU memory. The data will still have to be transferred over the bus though.
Draw map image @ my pixel scale
All of my game projects have been like that up until now. The problem is that without somewhat proper OOP I... get entangled. It's a pain to get into old projects too...
My map is 95 + 3 rows of sentinels, only 1 drawn. Here some guy managed to escape. He's at Ypos 100 and is doing a +1 check in the array. I can't see him, but he would be outside of the screen. Maybe I've just missed a Xpos,Ypos when copypasting, doing a Xpos,Xpos or some crap like that. No wait. I don't HAVE any actor-tile collisions yet. Haha. Oops. No wonder they wander off into the wild.
Anyways, 500 guys on screen, only a few Millisecs extra for all collisions (except actor-tile). I'm probably safe.
It was a pain to get Actor-Tile collisions in. Lots of hard to catch bugs, like when I set the position (rather than reversing some movement vector) after a tile (wall) collision, I forgot to update the bucket grid, leading to some ghosts being left behind. Normally I set the bucket to null if I move an actor out of it. Whatever, now it works. Here's a few guys (reduced to dots) with the buckets in gray.
There's a lot to optimize still, but I did some stress tests and I'm probably safe, at least on this machine. I can probably push it down some 3-6ms or so. The bots and shots are actually 16*16px images, each scaled up 2x by the GPU, so that's 800 images and 1000+ 4*4px images for the map. The map is 10 000 cells but I don't draw the black of course. Later I'll try and see if I can pre-generate the 2x scaling (if that's faster) and not redraw the whole map every frame. Afaik the GPU is doing some thread stuff, because I can't really measure drawing time from my program. It's probably iterating all the cells and objects that's slow.
And yeah, I probably won't have this many actors, and often the player will be rather alone, so that reduces the number of checks. The separate bullet lists are meaningless now, all bullets can collide with all actors (except the owner). Later I might make some kinda of friendly fire phase weapon though.
Still have a bug with escapees. I think what's happening now is someone getting too much speed from some knockback code, ending up inside a wall, then wall warping out of the playfield past all of my sentinels. The solution is to:
A bit in the tile collision code, which checks for wall stuckage, then figures out what edge the actor is close to and gives him a nudge. Or, better, the outer edge of sentinels could be special, and have a directional warp thing going.
Actor Tile collision code isn't working, and after 6hrs of debugging I still don't know what's up. The tile collision code is working, just not when actors are around. I think somehow actors manage to set their positions badly, causing them to go in the wrong bucket, causing other actors to be pushed away. (The actors see both Terrain and Actor buckets as obstacles.)
I'm gonna code the level class instead. It'll manage level data and setting up levels / waves.
Bought a Joypad (dual analog PS clone), mouse (mightymouse sux) and headphones. I'll probably do a dual analog thing of this. A 360 Robotron kinda thing.
Worked some on blips. I have a new idea. Instead of the family in Robotron, I you can pick up your coop bots in Zerberk. These shoot the enemies, and as you pick them up you get a score, but limit your team's firepower. But if they are valuable to the player, they can also be valuable to the enemy. I'm thinking that if a coop bot dies, it leaves a pellet, or enhances its killer. That's why the enemies wants to kill them too, and why I have drawn upgraded versions of the blips. They just have more HP and shoot more.
Another idea for an enemy is something like the Factories in Robotron. If these upgrade they start pumping out super units. Watto, the "kills you if you're camping" (Otto) enemy is a super enemy and maybe also upgrades all enemies near him. Coding behaviour for the different units won't be that hard, I have a lot of functions in my abstract classes that I can combine.
Oh, yeah, I've put a flash or team color on a separate frame. I like how the stuff in Robotron flashes, it's a good way to pull attention. Flash and animation for enemy bullets. Player bullets can be static and gray because the player knows where his bullets are (predicting with his imagination). I'm also color coding the enemies so they can be identified at a glance.
Still haven't found tile collision bug.
Drew some diagrams of the classes.
Realized that I have a blood gore class which already draws a 400*300 image in my older game, Robotroid. Now, that's about the size of my playfield, 768/2. Realized that I can combine that with the map image. The blood class draws bloodsplatter, but it's easy to filter so it only draws on black pixels. The destruction levels on my wall tiles actually removes pixels (plots 2 new black), so I really only have to plot a few pixels on a tile that's changed. Anyways, solves my map drawing problem.
Here's the old Robotroid project. I have a playable version of it, multiplayer coop, but then I rewrote it with more proper OOP cuz it was getting unmanageable.
Well, a program is really just a very detailed design doc, isn't it? I tend to get carried away with details though.
I think I'm onto the bug.
My actors have a RADIUS (or half box width) of 0.5 now, and the playfield cells are 1.0. Of course since I want the actors to be able to fit into tight spaces, I subtract a bit from the radius to make a smaller box. I use the radius for distance checks which bumps the actors away from each other, so normally they don't get a chance to actually tile check against each other. But I've disabled that code now.
The Actors have an Xpos, Ypos, Xvel, Yvel, all floats. The velocities are accumulated in various functions, like getting hit, moving about, bumping into stuff. I add the velocities to the positions. This would normally be the only place in the code where positions are set, but with the tile collision code I needed(?) to brute set positions and zero velocities.
Xpos, Ypos is the center point of an Actor.
Bug: Tile collision is working for the Terrain (blue tiles) (Edit: no, it's snappy for the down angle.). But another dimension of the map contains Actors. If they do, AND these Actors move about, then some Actors manages to find their way into occupied cells, causing them to snap around and do the classic stuck in wall crap we see in games.
The bug might have to to with a float discrepancy between setting the corner spots of an actor and then setting the center position in the collision code. I think. At least the bug became a lot less pronounced when I noodled around there.
' This func should be the only place where I set Xpos and Ypos. ' I start by clearing the bucket, then I do stuff, then I set the bucket. Method MActorToTileCollisionTest() If TMap.Actor[Int(Xpos),Int(Ypos)]=Null Then TMain.FNote("What the Hell???") ' Happens. TMap.Actor[Int(Xpos),Int(Ypos)] = Null ' Clear Own bucket ' My Tiles and Actors are 1.0, so lets make them a little smaller. ' Actor positions are center handled. Local oldtopspot:Int = Ypos-(RADIUS-0.05) Local oldbottomspot:Int = Ypos+(RADIUS-0.05) Local oldleftspot:Int = Xpos-(RADIUS-0.05) Local oldrightspot:Int = Xpos+(RADIUS-0.05) Local newtopspot:Int = Ypos-(RADIUS-0.05) +Yvel Local newbottomspot:Int = Ypos+(RADIUS-0.05) +Yvel Local newleftspot:Int = Xpos-(RADIUS-0.05) +Xvel Local newrightspot:Int = Xpos+(RADIUS-0.05) +Xvel If Yvel<0 ' TOP L,R (bias) If TMap.FTileIsObscured(oldleftspot, newtopspot) Or TMap.FTileIsObscured(oldrightspot, newtopspot) ' True if occupied by Terrain/Actor. Yvel = 0 ' Can't go there. MAddVelocity() will not add Yvel. Ypos = newtopspot + 1.0 +(RADIUS-0.05) ' Centerhandle on old, presumably free cell. EndIf ElseIf Yvel>0 ' BOTTOM L,R If TMap.FTileIsObscured(oldleftspot, newbottomspot) Or TMap.FTileIsObscured(oldrightspot, newbottomspot) Yvel = 0 Ypos = newbottomspot - (RADIUS-0.05) EndIf EndIf If Xvel<0 ' LEFT T,B (bias) If TMap.FTileIsObscured(newleftspot, oldtopspot) Or TMap.FTileIsObscured(newleftspot, oldbottomspot) Xvel = 0 Xpos = newleftspot + 1.0 + (RADIUS-0.05) EndIf ElseIf Xvel>0 ' RIGHT T,B If TMap.FTileIsObscured(newrightspot, oldtopspot) Or TMap.FTileIsObscured(newrightspot, oldbottomspot) Xvel = 0 Xpos = newrightspot - (RADIUS-0.05) EndIf EndIf ' Add Xvel, Yvel to Xpos, Ypos. MAddVelocity() ' Go into my bucket. It should be safe, but isn't cuz of bug. TMap.Actor[Int(Xpos),Int(Ypos)] = Self End Method
Yeah, the TMap Type (Class) isn't properly encapsulated.
Edit: I just realized that since my RADIUS is both a box for tiles and a circle for bumping, bumping won't happen in diagonal situations. I can make the bumping radius larger though, but because I use the 8 neighbour buckets to look for bumpable actors, the radius' extra reach is meaningless if two actors are horizontally or vertically aligned. But bumping inaccuracies are not a huge deal since movement is kinda random anyways. Bumping is just there to emulate social/private zones (like strangers not standing close to each other if there's room).
Edit: I should be adjusting my new top/bottom spots if there's a collision, shouldn't I?
Well, I fixed the code so the corners are updated properly. However, the bug persisted. However:
By using a seed I was able to catch the bug at a precise moment, then replicate it in slowmotion.
With my small scale I can't really plot the corners, so I was locked into a grid mindset. I didn't realize that actors exists on fractions, giving rise to situations like this:
...where the pink one moves into free bucket and the green one gets its corner spots fucked by the cell below it suddenly becoming set as impassable. My tile collision code can't handle that shit since it relies on knowing the velocity to nudge stuff into a legal position actively.
Haha! I fucked the bug in the ASSSSSSSssssssss!
Basically, I skipped tile collisions and just made the walls 'repulsive' just like other actors. This also solves the directional sentinels problem. If an actor is stuck (due to extreme speeds or some tunneling crap) in one tile into a two thick sentinel wall, like:
wwo wao wwo
then the walls (w) will repel the actor (a) back into the open (o) playfield, because the open cells does not repel it. Normally they stay a bit away from the walls now (depending on my repulsive constant), which is fine. Gotta figure out a way to reduce the jitter though. I'm thinking of making actors deliberately plot a course away from walls to stay more in the open.
Cake: yeah, that was my first idea, but I wanted to try this one out first, since I already had code for it.... Well, see how it goes...
It seems to work to plot a course away from the wall. I just set the angle to straight away from the wall. Perhaps the angle should bounce, but it looks more robotic if the actors align to 90 degrees every now and then. They sometimes follow the path of a corridor that way.
Anyways. My actors are only checking LoS against the closest enemy actor of the enemy list. This means that occasionally (1/20th chance) the actors have to scan the entire enemy list and do a Pythagora. Now, that won't do, since the closest actor can be behind a wall and the next closest can be in plain sight. So, I tried throwing in my LoS thing against every actor, then returning the closest with LoS. I disabled drawing and got a 2-4 ms count for all physics (bullets, bullet-actor, actor-wall, actor-actor, ai, moving about, damage) for 200 actors of a random team (Evil/Good).
Not too bad, but here's my machine. I'll have to run the program on an old Win Laptop and see what happens.
Intel Core 2 Duo - 3.06 GHz 2 GB 800 MHz DDR2 SDRAM NVIDIA GeForce 8800 GS
I've got a laptop that's 1.5 GHz, WinXP, 512mb. I think it will go well above 10ms... I can't go over 15-18ish or whatever. 1000/60fps. I think I can speed up drawing a lot though. Right now when I enable drawing with the zillion LoS rectangles, I get:
High ms clock is mostly the LoS rectangles drawn stacked on top of each other. I'll have to do a separate physics and draw ms clock.
A new TClock class now measures physics, drawing and total. Gives out an average for 32 frames.
1.5ghz, Oldish WinXP Laptop, 6 - 7.5 ms. physics/update.
My iMac, 2.5 - 3.8 ms. physics/update. (With my old single LoS routine, around 1 ms.)
...for 200 robots. It seems I'm somewhat safe. I can probably optimize the code a bit later too.
Now using flashing color indexes on the units. It's not really indexes since I'm in 24 bit or 32 bit, so I use a separate image.
Just having fun. I'm thinking of adding a bunch of shadow colors so I can be more artistic with the sprites. Tomorrow I'll tackle the map drawing problem and gibs. Maybe pretty the game up a bit.
Also, a simple counter class which... counts to various numbers (like 0-4) with certain speeds. Good for global animation stuff.
Zerberk was a brainfart name, but it might stick.
Got up, realized that my LoS routine already does a Pythagora, so I could return that rather than a boolean. That saved me a lot of Pythagora in another heavy routine (find closest visible actor on other team).
Also realized that I can make the player use the existing LoS code, or a modified version, but draw enemies as radar dots if the enemies are not visible. Perhaps:
Visible: Draw 'sprite'.
Not visible but close: Proximity sensor, draw a radar dot.
Not visible and far away: Draw nothing.
Everything in the friendly list would be visible. Perhaps I can use the LoS scans which I already run with the friendly side actors. I could just put a visibility tag on the actors on the enemy side in the same go.
I might have to check enemy bullets too. I have a bullet list for each team. Although, perhaps all bullets are visible and anyone who fires and is on the enemy team gets a visibility tag.
Not sure if this would make the game more exciting. It's not fun to have to look for enemies, but the proximity radar dots could fix that.
One problem is that the ai's scans are infrequent, every 20 tick or so (rnd), so the player/s would have to scan more often. It wouldn't be a burden since there are so few players.
Just a stress test. I should be working on that LoS visibility presentation code.
Visibility is in.
Dark Gray dot: Not visible (I just draw it to debug)
Gray dot: Radar dot of sorts. Sensed through walls.
Gray silhouette: Just seen, or self-revealed by firing. Since I don't do bullet LoS I figure that anyone firing would reveal themselves, since you can tell by the bullet style anyways.
Green guys are the good guys here. The Grunts are enemies and not always visible.
Fairly easy to implement, but I still had to spend an hour looking for a typo. :/
My plans in ruin!
Because pixmaps are probably not GPU (afaik, they're in the regular memory, software render or whatever), the SetScale command (GPU/OpenGL) does not affect them. I use that to 2X everything. I almost had the bloodsplatter class in. Yes, robots do bleed.
Oh well, I suppose I can try drawing on the backbuffer then grabbing. On the bright side, that's more convenient since I don't have to worry about bounds, and strange peek/poking.
I'll have to do some benchmarks.
My plans in ruin!
Benchmarks first gave me 30 ms to grab a 388,388 image. Drawing the same image at 2X doesn't take any significant time though.
Then I realized that alpha and masking crap was on, so disabling that I got down to 5-15 ms. Still way to slow.
I guess I can make a 2X pixmap, then plot manually at 2X. Basically I only need to plot the whole thing at level start, then I only have to update the destroyed parts and blood spots. Gonna benchmark it.
My plans in ruin!
14 ms just to draw the 388*2, 388*2 pixmap.
Strangely, a pixmap that's just 388,388 takes 2.2 ms, so that's 8.8 for 4 pixmaps...
I just tried grabbing 40 by 40 pixel cells, but they are still 1.7 - 16 ms each. Varies a lot. The idea was to only grab the chunks of the playfield map that were changed.
What the hell? An old Amiga could do this shit faster.
Last resort: Every little thing is an entity or tile which I redraw every frame. I've already tried making dying guys into corpse tiles, and it works. They just make a little wall where they died, but graphically this wall tile could look like a body, and I could do blood splatter tiles too. Maybe some particles which disappears.
Pity about the blood though. I had the class done. It sends gibs sliding across the floor, leaving trails (based on various inherited velocities).
I think I can make the background (I plan to decorate the black BG a bit like in BQ) into a big unchanged image at least. It might be faster to draw that as a whole, not sure.
I'm drawing my 2x in windowed mode btw. The pixmap solution would work if I do fullscreen because then some OS thing would scale the game canvas. 2.2 ms for the 388,388 image is not too bad.
I can't scale to 2x.
As I understand it:
Images are in the GPU mem and can't be edited, but are really fast to draw. Transferring stuff into the GPU is slow, so I can't draw stuff on some buffer then toss it into the GPU on the fly.
Pixmaps are software render stuff (no GPU), slow to draw, but can be edited since they're in regular memory. But, it's the GPU that does the 2x scaling which I use in windowed mode. I can't use that on Pixmaps.
Drawing is still a bottleneck. If I fill the screen with a lot of tiles, 50% or so, that's 5k tiles, and it takes some 5-7ms to draw (or atleast to cue up for drawing, because I'm pretty sure I can't benchmark the GPU).
On level init, draw everything on the map, walls and background decoration (I plan to make little lines and stuff like in BQ). I Grab that (slow), but I don't update the image after that (not until the next level). I just keep drawing it in the background. Instead I put the changes to the map in an array and just draw the changes. The more destruction, the slower it gets as there are more tiles to draw. The destruction will mostly be walls and some dirt on the floor, so perhaps it will be faster as long as the player doesn't go anal, destroying every wall, etc. Also, I have a border which can't change, so I don't need to iterate that, going down from 97^2 to 95^2 cells.
I'm afraid I'm a rather mediocre programmer, but I am learning. OOP has helped me to structure things, and it really helps when doing a project of this magnitude. Today I renamed all my map dimension constants so I know whether they are units, pixels or double pixels. Lots of places to change, but I'm beginning to learn to write self documenting code by using good variable and function names.
The solution seems to work. Drawing the static BG map doesn't take much time at all. Also, as the enemies are killed, there is less to draw, but by then there's a fair amont of destruction, which is slower to draw, so it kinda balances.
Here the static BG map is gray, and change is red. (Radar dots green).
^It's what the posts above are all about. I draw the robots over the background, ruining it. I don't feel like doing dirty rects, and I can't save/copy the BG image fast enough. It's probably possible with another language, who knows... anyways, what I have now is faster than what I had before, because drawing a single image is faster than drawing many tiles.
Now I'm doing some graphics! Maybe tomorrow I'll have them done so I can spice up the black floor, and add some gibs, corpses.
Just got up, and got an idea:
My terrain layer is an array of bytes, then I have an actor layer with pointers on top of that. So, if I want to have larger, but static and destructible... doors, buildings, whatever, I can:
I a bullet hits a terrain bit, and the value of that terrain bit is, say 254, then that means that I should look in the actor layer for the thing to damage. So I get the actor pointer, and do stuff with the thing pointed to. If it's destroyed, I can look at the width, height and corner handle of the thing, and clear all of its cells.
Terrain 254,254,254,0,0,0 254,254,254,0,0,0 254,254,254,0,0,0 Actor *56,*56,*56,0,0,0 *56,*56,*56,0,0,0 *56,*56,*56,0,0,0
then *56 would be an instance of a class inherited from my basic blip with the properties Xpos,Ypos,Width,Height, Hitpoints and various methods and functions. It could be a turret, door or power generator. Its destructor would clear the cells that it occopied (and produce rubble and particles).
Edit: Actually, I might not need to do a check against the Terrain at all since I already check against actors in the actors array. There's a difference though: billets colliding with the terrain use the center of the bullet and no radius, whilst actor vs actor collisions use the radius of both the bullet and the target's body.
Also, instead of coding a sparks/debris/explosion class, I could just use a type of special short lived bullets. This means that the player could set of chain reactions, if I do an enemy that is just a static explosive barrel. It would simply just shoot randomly in its destructor. Although, that would slightly Thwart my plans to have bodies turning into terrain objects, because the bullets would hit the corpse tile. I would need to .. ah, yes, figure out which tile the corpse goes in, then create the bullets radially spaced from that. Or I can disable terrain checks for these bullets if their lifetime is young, but keep actor checks.
Actually, I'll draw the debris of a static actor on the background image, so when a large static actor dies, it simply reveals its debris... may or may not work.
Anyways, today's progress:
Made new graphic sheets for small tiles, floor tiles, and finished a function which spices up the BG a bit.
Worked some more on the actor gfx, but it's not in yet.
Made a separate particle sheet, no longer keeping bullets on the actor sheet (which has relatively huge cells). Particles will be also be sparks and explosion stuff. I have an idea that the blue walls will send off blue particles when damaged so it looks like parts being chipped away.Here are two actors flailing their aim at each other. They don't shake it randomly. The oscillation is due to the momentum of the aim as they try to steer it towards the ideal angle. I'm trying to emulate human behaviour with the AI, giving the bots a virtual joypad, a sluggish state of mind rather than instant reaction time, etc.
Gibs! Corpses! It looks neat shooting the walls, and the actors just don't go poof, there's a transition to their nothingness with particles and corpses (also gib'able). Not sure about explosion images, I already flash the actors when hit, and there's particles flying off. They have HP, so I'm thinking I must show damage state somehow. Perhaps blink them red and send off a red gib, kinda like the CC bleeding. Yes, the robots bleed, because that's in my story. They process humans and make blood fuel or something along those lines. I've already pixeled some of their blood tanks.
Static screenshots looks a bit messy, in motion it's easier to tell what's going on.
I want the universe to feel real, so I'm gonna put crates in some rooms. That will spice things up. Yeaaaah, Crates baby.
Ok, so I need something more than crates and nonsense rooms.
I somehow need to explain why the robots have built a large array of nonsense rooms. And what the robot's agenda is. I can imagine that they are a large force, and they invade planets and stuff. So, what kinda stuff can I populate the levels with if the robots are to make any sense logistically and so on?
First, they are EVIL. They kill humans, process them for blood which they use for fuel. They also need to build robots and invasion fleets. Doing that takes power.
ROOMS: + Prison (human containment). + Human processing station. + Power plant. + Mine. + Ore->Metal processing/refinery. + Robot factory. + Shipyard. + Some moon buggy or parking lot. + General storage (ore, metals, power(explosive), items...). + Troop storage. + Blood repository. + Computer core. + Main computer (boss?). + Mystical device. + Large turret. + Shield gen or some field... generating thing. + Teleport pad.
The ship will be an image drawn over the tiles. The crane will move back and forth with the modules. Welding and upgrading. To the left, Blood repository and computer core. These will be static actors drawn over the tile map. I plan to make the tile map of the rooms as BASIC Data style statements. In the case of actors which are invulnerable, I simply leave the tile map as invulnerable tiles and don't link the actor in any bucket (just the global list).
UNITS: + Troops of various kinds. + Overseer (Watto). + Power loader. + Mechanic (can upgrade low level robots). + Small turret. + Suicide rusher. + Mobile factory (perhaps it just places things that are produced by a larger Factory). + Converter (makes humans into evil troops).
Quick and dirty editor. It does borders automatically (copypasted routine from rnd map gen) (Perhaps I can copy paste the editor into the game later). I'll reprogram it to suit my intentions as I go. Right now it just prints out BASIC style Data rather than saving to a file. I'll inject those Data lines into my game of course. I'll set the width and height to whatever room size I want. The shipyard will be about this size, except I'm just painting nonsense here.
Yesterday I did some low health 'red blink' indication and bleeding (sparks/blood that flies off randomly).
Made a save area, actor positioning, and toggle for BG color so I'll notice any black empty tiles that I might have placed. I have a lot of solid black tiles which I have yet to draw stuff on. I'm using a byte for the map (unsigned char in C iirc), so I have 256 tiles max. Also did a cleanup function to remove BG tiles. I should do a picker but ran out of mouse buttons. Might have to use the alt key for that.
Also formatted the text output so there's extra spaces that align the numbers (e.g. __0,_10,100). Makes it more readable if I want to hand edit.
Room data now injects where I tell it to, and spawns a number of associated actors. I'll have to use IDs for the actors so I can name them in the Data. Here of course it's just my test enemy disguised as a crate.
There were some quirks with the floor borders, which I needed to generate after injecting the rooms.
I'm thinking each level will load a number of rooms on static positions, but the other walls are random and all (or most) of the enemies are randomly positioned.
Ran into some snags, like needing invisible walls under the actors who are static and hovers above the playfield. The images of those actors will have transparent black showing through, and I didn't want to use magenta masks. Besides, invisible walls might be useful in other ways, like particle forcefields. I had to rearrange my tiles and change how the game recognizes invulnerable tiles. Also needed to tweak the border algoritm since invisible tiles shouldn't have a border generated around them despite being solid.
Also made a quick overlay thing so I can load reference images in the map editor.
Well, they load properly and the invisible walls seem to work. I'll put a forcefield / stargate at the top of the hangar bays. Tomorrow it's time to tackle the doors I think. I've preparing my classes a bit for that. I'll try placing them in multiple buckets (3). Then my bullet vs actor bucket collision code will hit the actor as if at multiple places at once. We'll see how that goes. The shipyard will need a bit more work as it has some 'scripted' movement with the crane. I've started on the class though.
I'm not sure if I should do Y ordering, for overlaps. I might be able to use some kind of horizontal buckets for that. I already have buckets of course, but they're 4 px (x2) high. It's pretty low on the list anyways. Here the actors are tight because they're spawned as if crates and doors.
Other stuff happened.
Drew some gfx for the first level. Drop ships. Trees. You assault the entry with your coop bots.
Since all my bots control a virtual joystick, I had the idea that the player could transfer to another body when he dies if he's close enough. It's just a matter of changing a pointer or two. It's a possibility at least. I'd like to somehow allow the player to infiltrate enemy units. Perhaps there are stealth / infiltration levels where the player has just hacked into an enemy unit. That would just be a matter of a switch in the player spawn function. We'll see, it's way further down the road.
Made the level initialization function into a huge simple Switch so I can do all sorts of custom stuff for each level. I had some instanced crap before which just wasn't dynamic enough.
Also thought some about my various static actors, made tables of their properties so I can see what they need to share and how many classes I need to make.
It's Asteroids Day apparently (30y), so I was gonna write something real quick. Not very interesting at all, as I didn't get very far. Sauce.
I was in Phoenix, AZ at this time. It was difficult to get back into the code, but luckily it was doable, since I kept it pretty clean. It's dangerous to write sloppy code to get stuff working, just before dropping the project.
I implemented destructible crates which created debris. Chain reaction worked as planned. Also split the enemies into two sides (top and bottom of screen) just because it looked cool to watch them have a shootout then storm the survivors. (If an enemy doesn't see anymore targets it might try to approach the last seen position.)
I also bought a 360 joypad with the intent of making the game work with it. I think it maps things a bit differently than my PlayStation joypad clone. Also, I'm suspecting that implementing player movement will be hell, because right now the enemies move away from the walls willingly, whilst the player will not (although I could force the ingame avatar, perhaps).
The game runs pretty badly on Netbooks, because of a poor GPU (probably integrated something). It runs faster when scaled to 1x. It runs slower if parts of the canvas is outside of the screen. It runs badly on a larger external screen.
Compiled this page. I have some art which I need to scan. It's not too late to finish this thing and complete my resolution, but I have so many other things to do.