Cool. Yeah, definitely need power-ups! But after playing Zodiac I don't think that will be a problem. Heh. And yeah, you shouldn't be loading any resources on disk every frame! Not good.
Sure, send me a line. You also might want to think about putting your project under version control. It lets you track and undo changes to any file, view previous versions, helps with tracking down newly introduced bugs, etc. It also acts as a back-up in case something bad happens, and is pretty much the easiest way for someone else (or a team) to deal with working code. There's also private repositories if you want it out of public view; I think bitbucket still offers that for free. If you ever need input on stuff or want to get me in chat, or anything else like that, you kind of have to PM me first--it's not that I'm busy in the evenings, it's just that I don't really meander around the internet as much these days.
Awesome idea #1: The Soldier is actually a bio-suit with a smaller (possibly flying) tank that comes out!!!
Im using dropbox for backups at the moment, but it's not really set up for collaboration, just backup. Once I get things in some semblance of what I THINK is order, I'll look into that if you wanna join the project in an overseer-type capacity. ("Hey, knucklehead, you're gonna cause slowdown unless you fix X and Y...")
Also, your Awesome Idea #1 is VERY CLOSE to something I have planned! One of the item types for the Soldier I have planned are little helper robots that to various things. Some will be like Item 1, Item 2, and Item 3 from MM2, and others will do other things. (Hence why Doodads as a separate game object are so important). A small tank-like thing is not out of the question!
Eh, it's just the regular collision detection function (is there a spike at your X coord plus your X velocity) with an added check to see if you're standing directly on top of it while not moving. I'm sure ZClassic does it similarly in sideview, but it counts "standing on" as being one tile above it rather than actually touching it.
One thing I always thought would be cool with a Blaster Master game is having the camera zoom in when you jump out, so your character is more normal sized and whatnot, and zoom back out when you re-enter your vehicle. If the zoomed-out artwork is fine enough, you could just zoom all the pixels to 2x2 pixels in zoomed-in view; it would look more pixelated - but that isn't really a bad thing to people like me. Alternatively, you could make more detailed tiles for everything and just transform from one to the other as it zooms - dunno how that would look or work out though.
Anyways, your character isn't as small compared to the tank as in Blaster Master, so it's not really a suggestion for your game here, just ramblin'. Agree about the overhead areas - they were the worst part of BM. I have faith you could make them interesting, but I also suspect your desire to omit them is the best option.
But yeah, looking forward to eventually playing this too. You got real talent, man. I wondered what your artwork would look like, not restricted to ZC, and wow, this is fantastic.
I can't get friggin' doodads to spawn properly. Doodad inherents float x from GameObject class, but when I try to spawn it at a particular x coordinate, it keeps spawning at 0,0. Because... reasons? Argh!
Anyway, I did tweak some of the code controlling collision detection so that those jump-up-but-not-down type blocks work. You know, like hills in SMB2. Also found and voided a bug that had caused slow movement when you're in a different room from the tank.
I can't get friggin' doodads to spawn properly. Doodad inherents float x from GameObject class, but when I try to spawn it at a particular x coordinate, it keeps spawning at 0,0. Because... reasons? Argh!
Anyway, I did tweak some of the code controlling collision detection so that those jump-up-but-not-down type blocks work. You know, like hills in SMB2. Also found and voided a bug that had caused slow movement when you're in a different room from the tank.
Does the spawn use a different class than the doodad? If so, that alone could cause the problem.
Try something along the lines of:
spawn_doodad(doodad.x, doodad.y);
Edit - ACTUALLY the problem is most likely that you're spawning a doodad that doesn't exist yet, so any variable assigned to it is irrelevant. Instead, try passing the x and y variables to the class that your spawn function is located within.
Edited by Anarchy_Balsac, 11 October 2015 - 07:48 PM.
I dunno about that. Here's some relevant bits of code.
This little jobber lives in GameObjectManager and keeps an eye scanning the on-screen tiles for one that indicates an instruction to spawn a Doodad:
// SPAWN DOODADS
if((CurrentBlock->user1>=DOODAD_RANGE_START)&&(CurrentBlock->user1<=DOODAD_RANGE_END)){
fprintf(stderr, "X calculated by GameObjectManager = %f!\n",searchX-xOff);
CreateDoodad(CurrentBlock->user1,CurrentBlock->user3,searchX-xOff, searchY-yOff, 0,0, xOff, yOff); // Need to un-correct for offset before spawn
MapSetBlockInPixels (searchX, searchY, 0);
}
Heres' the function it calls (in relevant part). You can see all my trace prints along the way:
void GameObjectManager::CreateDoodad(int doodadType, int doodadSubType, float x, float y, int dirX, int dirY, int xOff, int yOff)
{
ALLEGRO_BITMAP *setup_bitmap = NULL;
int velX = 0;
int velY = 0;
int boundX = 0;
int boundY = 0;
if(doodadType == MOVING_PLATFORM_VERT){
Floating_Platform_Doodad *bornDoodad = new Floating_Platform_Doodad();
bornDoodad->Init();
setup_bitmap = al_create_bitmap(64,64);
al_set_target_bitmap(setup_bitmap);
al_clear_to_color(al_map_rgb(255, 0, 255));
setup_bitmap = al_load_bitmap("MarsFloatingPlatform.png");
int boundX = 64;
int boundY = 64;
dirX = -1;
dirY = -1;
fprintf(stderr, "X use to call Doodad::Spawn = %f!\n",x);
bornDoodad->Spawn(x, y, velX, velY, dirX, dirY, 128, 64, setup_bitmap);
fprintf(stderr, "Doodad X = %d!\n",bornDoodad->GetX());
fprintf(stderr, "Doodad Y = %d!\n",bornDoodad->GetX());
// Set up movement; vertical doodads move along Y axis only, and move up and down from spawn point
// in distance measured by user2.
bornDoodad->ProvideRunData(bornDoodad->GetX()+xOff,bornDoodad->GetY()-doodadSubType+yOff,bornDoodad->GetX()+xOff,bornDoodad->GetY()+ doodadSubType+yOff);
fprintf(stderr, "first X = %d!\n",bornDoodad->GetX() );
fprintf(stderr, "first Y = %d!\n",bornDoodad->GetY()-doodadSubType+yOff );
fprintf(stderr, "second X = %d!\n",bornDoodad->GetX()+xOff );
fprintf(stderr, "second Y = %d!\n",bornDoodad->GetY()+ doodadSubType+yOff );
doodadList.push_back(bornDoodad);
}
}
Here's the chain of inheritance for the Floating_Platform_Doodad class:
Spoiler
#pragma once
#include <iostream>
#include <allegro5/allegro5.h>
#include <allegro5/allegro_primitives.h>
#include "Globals.h" // I want game objects to have access to global variable
#include "mappy_A5.h" // I want game objects to have access to the size of the tile map, so I'll include the header.
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_acodec.h>
// Every other object is going to inheret from here, so we put a lot of work
// into this object.
class GameObject
{
private: // Accessible ONLY inside of this class, Game Object
int ID;
bool alive;
bool collidable;
protected: // Accessible ONLY inside this class or any class that inherets
int x;
int y;
float velX;
float velY;
int dirX;
int dirY;
int boundX;
int boundY;
// Animation variables
int maxFrame;
int curFrame;
int frameCount;
int frameDelay;
int frameWidth;
int frameHeight;
int animationColumn;
int animationDirection;
int damageCounter; // used for the period of animation after being hit
int invulCounter; // used for invulnerability periods after being hit
int impactBlinker; // used for blinking the impact star
int power;
ALLEGRO_BITMAP *image;
ALLEGRO_BITMAP *impactSprite;
public: // Accessible by anyone
// CONSTRUCTOR / DESTRUCTOR
GameObject();
void virtual Destroy();
// These are the "big three" game loop functions.
void Init(float x, float y, float velX, float velY, int dirX, int dirY, int boundX, int boundY);
void virtual Update(int xOff, int yOff);
void virtual Render();
// ---- ACCESSORS AND MUTATORS
// We declare these in-line because they're so simple.
float GetX() { return x;}
float GetY() { return y;}
// Normally, I could have say x = x, compiler has no idea. We have one x that's global
// and one local to SetX. Normally you'd just name the "float x" down here something else.
// However, when I type this, I want to have the user prompted to input an "x" when they're
// using SetX. So we use "GameObject::x" to refer to the global x in our object.
void SetX( float x ){GameObject::x = x;}
void SetY( float y ){GameObject::y = y;}
int GetBoundX(){return boundX;}
int GetBoundY(){return boundY;}
int GetDirX(){return dirX;}
int GetDirY(){return dirY;}
int GetVelX(){return velX;}
int GetVelY(){return velY;}
void SetVelX( float velX ){GameObject::velX = velX;}
void SetVelY( float velY ){GameObject::velY = velY;}
int GetID() {return ID;}
void SetID(int ID) {GameObject::ID = ID;}
bool GetAlive() {return alive;}
void SetAlive(bool alive){GameObject::alive = alive;}
bool GetCollidable() {return collidable;}
void SetCollidable(bool collidable){GameObject::collidable = collidable;}
bool CheckCollisions (GameObject *otherObject);
void virtual Collided(GameObject *otherObject);
//This combines GetAlive and GetCollidable into a single function, or it will.
bool Collidable();
void virtual Jump();
void virtual ReleaseJump();
void virtual PressDown();
void virtual PressLeft();
void virtual PressRight();
void virtual PressFire();
void virtual ReleaseFire();
int virtual GetTouchDamage() {return 0;};
void virtual SetTouchDamage(int touchDamage){};
int virtual GetAttackDamage() {return 0;};
void virtual SetAttackDamage(int attackDamage){};
int virtual GetPower() {return power;};
int virtual GetItemType() {return 0;};
};
Doodad.h1
Spoiler
#pragma once
#include "Globals.h"
#include "GameObject.h"
#include "mappy_A5.h" // I want game objects to have access to the size of the tile map, so I'll include the header.
#include <stdio.h>
// This makes it inheret from GameObject. Everything GameObject has, this has
class Doodad : public GameObject
{
private:
protected:
int animationCounter;
bool active;
bool alive;
bool isSolid;
// Tells other things how to interact with this.
int doodadType;
public:
Doodad();
void Destroy();
void Init(ALLEGRO_BITMAP *image = NULL);
// Spawn is like Init, but it will also allow the object to be created at a specific location, direction, etc.
void Spawn(float x, float y, int velX2, int velY, int dirX, int dirY, int boundX, int boundY, ALLEGRO_BITMAP *image);
// Virtual because all different projectiles may interact and animate differently.
void virtual Update(int xOff, int yOff) {};
void virtual Render(){};
// This function lets you give the Doodad some additional run data. What it does with this data
// is up to the particular kind of Doodad it is.
void virtual ProvideRunData(float runData1, float runData2, float runData3, float runData4){};
bool GetActive(){return active;};
void SetActive(bool active){Doodad::active = active;};
bool GetAlive(){return alive;};
void SetAlive(bool alive){Doodad::alive = alive;};
int GetDoodadType(){return doodadType;};
};
And then, finally, the class itself:
Floating_Platform_Doodad.h
Spoiler
#pragma once
#include "Globals.h"
#include "GameObject.h"
#include "Doodad.h"
#include "mappy_A5.h" // I want game objects to have access to the size of the tile map, so I'll include the header.
#include <stdio.h>
// This makes it inheret from Doodad. Everything Doodad has, this has
class Floating_Platform_Doodad : public Doodad
{
private:
int firstX;
int firstY;
int secondX;
int secondY;
int movingState;
protected:
public:
Floating_Platform_Doodad();
void ProvideRunData(float runData1, float runData2, float runData3, float runData4);
// This function lets you give the Doodad some additional run data. What it does with this data
// is up to the particular kind of Doodad it is.
void Update(int xOff, int yOff);
void Render();
};
Floating_Platform_Doodad.cpp
Spoiler
#pragma once
#include "Floating_Platform_Doodad.h"
#include "mappy_A5.h" // I want game objects to have access to the size of the tile map, so I'll include the header.
#include <stdio.h>
Floating_Platform_Doodad::Floating_Platform_Doodad()
{
}
// This function lets you give the Doodad some additional run data. What it does with this data
// is up to the particular kind of Doodad it is.
void Floating_Platform_Doodad::ProvideRunData(float runData1, float runData2, float runData3, float runData4)
{
fprintf(stderr, "X existing at time of ProvideRunData = %f!\n",x);
firstX = runData1;
firstY = runData2;
secondX = runData3;
secondY = runData4;
isSolid = false;
velX = 0;
velY = 0;
// Adjust variables for this kind of Doodad
movingState = 0;
doodadType = MOVING_PLATFORM;
frameWidth = 96;
frameHeight = 64;
}
void Floating_Platform_Doodad::Update(int xOff, int yOff)
{
// Moves between the two defined points.
int realX = x + xOff;
int realY = y + yOff;
if(movingState == 0)
{
if (realX + velX < firstX) velX = 2;
else if (realX + velX > firstX) velX = -2;
else velX = 0;
if (realY + velY < firstY) velY = 2;
else if (realY+velY > firstY) velY = -2;
else velY = 0;
if (abs(realX - firstX <= 4)&&abs(realY-firstY <=4 )) movingState = 1;
}else{
if (realX + velX < secondX) velX = 2;
else if (realX+velX > secondX) velX = -2;
else velX = 0;
if (realY + velY < secondY) velY = 2;
else if (realY+velY > secondY) velY = -2;
else velY = 0;
if (abs(realX -secondX<=4)&&abs(realY-secondY<=4)) movingState = 0;
}
x += velX;
y += velY;
}
void Floating_Platform_Doodad::Render()
{
// no animation
al_draw_bitmap_region(image, curFrame*frameWidth, 0, frameWidth, frameHeight, x, y, NULL);
}
Now, the Spawn function lives in Doodad.cpp, so that's here:
#pragma once
# include "Doodad.h"
#include "Globals.h"
#include "GameObject.h"
#include "mappy_A5.h" // I want game objects to have access to the size of the tile map, so I'll include the header.
#include <stdio.h>
Doodad::Doodad()
{}
void Doodad::Destroy()
{
GameObject::Destroy();
}
void Doodad::Init(ALLEGRO_BITMAP *image)
{
//GameObject::Init(0, 0, 0, 0, 0, 0, 32, 32);
if(image!=NULL){
Doodad::image=image;
}
}
void Doodad::Spawn(float passedX, float passedY, int velX2, int velY, int dirX, int dirY, int boundX, int boundY, ALLEGRO_BITMAP *image)
{
fprintf(stderr, "X passed to Doodad::Spawn = %f!\n",passedX);
animationCounter = 0;
curFrame = 0;
frameWidth = al_get_bitmap_height(image);
frameHeight = al_get_bitmap_height(image);
SetID(DOODAD);
if(image!=NULL){
Doodad::image=image;
}
active = false;
alive = true;
fprintf(stderr, "X before calling GameObject = %f!\n",x);
fprintf(stderr, "passedX to send to GameObject::Init = %f!\n",passedX);
//GameObject::Init(passedX, passedY, velX2, velY, dirX, dirY, boundX, boundY);
SetX(512);
SetY(512);
if(x!=passedX)
{
fprintf(stderr, "X and passed X not equal; trying again?\n");
x = passedX;
}
fprintf(stderr, "passedX at end of Doodad::Spawn = %f!\n",passedX);
fprintf(stderr, "X at end of Doodad::Spawn = %f!\n",GameObject::x);
}
The movement of the platform is screwy, too, but everything seems to stem from the Floating_Platform_Doodad's x, y, firstX, firstY, and so forth all being ZERO once the object is actually instantiated. Even though, according to the output I get from those trace prints, all the functions (methods?) are getting the right info.
Do you use a debugger, and do you know how to set a watchpoint? This'd be a good time for it. I don't see the problem immediately, but I'll look at it a bit longer.
I've only recently ventured into the dark realms of C++ in depth; havn't learned to use the debugger yet. I suppose now's as good a time as any, huh? I'll look up some resources on Visual Studio 2010 and give a look-see.
EDIT: By the way, THIS is the first print statement that gives me a 0:
fprintf(stderr,"X at end of Doodad::Spawn = %f!\n",GameObject::x);
Which is odd, since the line JUST BEFORE I told it to make x = passedX...