Here's the code (it's scattered around my program) :
How I create the Robot:
void BENDERBOT(ROBOTCOLORS color) {
RegisterRobot("Bender", color, &BenderActions, &PimpOutBender,
"resources\\images\\basic_robot.bmp", -1, -1, -1);
}
#SelectExpand
1void RegisterRobot
(char *robotName, ROBOTCOLORS color,
2 void (*robotActions
)(int),
void (*configureRobot
)(void),
3 char *customImage,
int x,
int y,
float heading
) {
4 int i, robotNumber
;
5 ROBOT newRobot
;
6
7 if (theGame.state
!= GS_SETUP
)
8 AbortOnError
(
9 "Call made to RegisterRobot() when game is not in setup state."
10 "\nProgram will end.");
11
12 robotNumber
= SizeLL
(robotList
);
13 if (robotNumber
== MAX_ROBOTS
)
14 AbortOnError
("RegisterRobot() Attempted to add too many robots.\n"
15 "Program will end.");
16
17 newRobot.ActionsFunction
= robotActions
;
18
19 switch (color
) {
20 case ROBOT_RED:
21 newRobot.color
= al_map_rgb(255,
0,
0);
22 break;
23 case ROBOT_GREEN:
24 newRobot.color
= al_map_rgb(0,
255,
0);
25 break;
26 case ROBOT_BLUE:
27 newRobot.color
= al_map_rgb(0,
0,
255);
28 break;
29 case ROBOT_YELLOW:
30 newRobot.color
= al_map_rgb(255,
255,
0);
31 break;
32 case ROBOT_PURPLE:
33 newRobot.color
= al_map_rgb(255,
0,
240);
34 break;
35 case ROBOT_TURQUOISE:
36 newRobot.color
= al_map_rgb(0,
255,
255);
37 break;
38 case ROBOT_WHITE:
39 default:
40 newRobot.color
= al_map_rgb(255,
255,
255);
41 }
42 if (HasNullCharacter
(robotName, MAX_NAME_LEN
)) {
43 newRobot.name
= malloc(sizeof(char) * strlen(robotName
));
44 strcpy(newRobot.name, robotName
);
45 newRobot.number
= robotNumber
;
46 } else
47 AbortOnError
("RegisterRobot() was passed a robot name exceeding "
48 "MAX_NAME_LEN.\nProgram will end.");
49
50 //Set starting speed values
51 newRobot.leftTreadSpeed
= 0;
52 newRobot.rightTreadSpeed
= 0;
53 newRobot.impulseHeading
= 0;
54 newRobot.impulseSpeed
= 0;
55 newRobot.turboTime
= 0;
56
57 //Configure the sensors.
58 newRobot.bumped
= BUMP_NONE
;
59 for (i
= 0; i
< MAX_SENSORS
; i
++) {
60 newRobot.sensorArray
[i
].type
= SENSOR_NONE
;
61 newRobot.sensorArray
[i
].image
= NULL
;
62 }
63
64 //Configure the laser.
65 newRobot.weaponArray
[LASER_PORT
].type
= WEAPON_LASER
;
66 newRobot.weaponArray
[LASER_PORT
].maxAngle
= LASER_MAX_ANGLE
;
67 newRobot.weaponArray
[LASER_PORT
].minEnergy
= MIN_LASER_ENERGY
;
68 newRobot.weaponArray
[LASER_PORT
].maxEnergy
= MAX_LASER_ENERGY
;
69 newRobot.weaponArray
[LASER_PORT
].bonusEnergy
= LASER_ENERGY_BONUS
;
70 newRobot.weaponArray
[LASER_PORT
].splashRange
= LASER_SPLASH_RANGE
;
71 newRobot.weaponArray
[LASER_PORT
].splashDamage
= LASER_SPLASH_DAMAGE
;
72 newRobot.weaponArray
[LASER_PORT
].speed
= LASER_SPEED
;
73 newRobot.weaponArray
[LASER_PORT
].bumpValue
= BUMP_LASER
;
74 newRobot.weaponArray
[LASER_PORT
].firingSound
= SND_LASER_FIRE
;
75 newRobot.weaponArray
[LASER_PORT
].impactSound
= SND_LASER_HIT
;
76
77 //Configure the missiles.
78 newRobot.weaponArray
[MISSILE_PORT
].type
= WEAPON_MISSILE
;
79 newRobot.weaponArray
[MISSILE_PORT
].maxAngle
= MISSILE_MAX_ANGLE
;
80 newRobot.weaponArray
[MISSILE_PORT
].minEnergy
= MIN_MISSILE_ENERGY
;
81 newRobot.weaponArray
[MISSILE_PORT
].maxEnergy
= MAX_MISSILE_ENERGY
;
82 newRobot.weaponArray
[MISSILE_PORT
].bonusEnergy
= MISSILE_ENERGY_BONUS
;
83 newRobot.weaponArray
[MISSILE_PORT
].splashRange
= MISSILE_SPLASH_RANGE
;
84 newRobot.weaponArray
[MISSILE_PORT
].splashDamage
= MISSILE_SPLASH_DAMAGE
;
85 newRobot.weaponArray
[MISSILE_PORT
].speed
= MISSILE_SPEED
;
86 newRobot.weaponArray
[MISSILE_PORT
].bumpValue
= BUMP_MISSILE
;
87 newRobot.weaponArray
[MISSILE_PORT
].firingSound
= SND_MISSILE_FIRE
;
88 newRobot.weaponArray
[MISSILE_PORT
].impactSound
= SND_MISSILE_HIT
;
89
90 for (i
= 0; i
< MAX_WEAPONS
; i
++) {
91 newRobot.weaponArray
[i
].chargeRate
= 0;
92 newRobot.weaponArray
[i
].chargeEnergy
= 0;
93 }
94
95 //Set starting energy priorites in same order as SYSTEMS declaration.
96 for (i
= 0; i
< NUM_ENERGY_SYSTEMS
; i
++)
97 newRobot.energyPriorities
[i
] = (SYSTEM
) i
;
98
99 //Set initial energy values. Weapons were done in the weapons section.
100 newRobot.shields
= START_SHIELD_ENERGY
;
101 newRobot.shieldChargeRate
= 0;
102
103 //Set structure-related values
104 newRobot.generatorStructure
= MAX_GENERATOR_STRUCTURE
;
105
106 //Robot has no damage to be applied at start.
107 newRobot.damageBank
= 0;
108
109 //Load the robot's graphic, if required. There is no error checking here as
110 //if newRobot.graphic is NULL, the graphics routines will simply use the
111 //default robot graphic to render the robot.
112 newRobot.graphic
= NULL
;
113 if (customImage
!= NULL
){
114 newRobot.graphic
= al_load_bitmap(customImage
);
115 al_convert_mask_to_alpha(newRobot.graphic,
al_map_rgb(255,
0,
255));
116 }
117
118 //Create the robot's bitmap.
119 newRobot.shield
= al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ
);
120 newRobot.image
= al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ
);
121 al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP
);
122 if (newRobot.image
== NULL
|| newRobot.shield
== NULL
)
123 AbortOnError
("RegisterRobot() failed to create robot image.\n"
124 "Program will end.");
125
126 strcpy(newRobot.statusMessage,
""); //No status message at start.
127
128 newRobot.mailBox
= ConsLL
(); //Create the robot's mailbox.
129
130 InsLastLL
(robotList, newRobot
); //Put robot on end of the list.
131 curRobot
= LastElmLL
(robotList
); //Record current robot for configuration.
132
133 //Set robot starting location. This is done only after insertion into the
134 //list because ChooseRandomLocation() requires the list to have robots in it.
135 if (x
< 0 || y
< 0)
136 ChooseRandomLocation
(curRobot
);
137 else {
138 curRobot->x
= x
;
139 curRobot->y
= y
;
140 }
141 if (heading
< 0)
142 curRobot->heading
= GetRandomNumber
(360);
143 else
144 curRobot->heading
= heading
;
145
146 configureRobot
(); //Call user's configuration function.
147}
The image is stored in newRobot.graphic at the 112-115th line. Also note that if, when I call the RegistewrRobot and customImage = NULL the program gives it the default image and it work fine but if I give it the path to the default image it gives me artefact.
Then this is when I draw the robot :
#SelectExpand
1void DrawRobotBitmaps
(t_LL listOfRobots
) {
2 float shieldCenterX, shieldCenterY
;
3 float drawAngle, modifier
;
4 ROBOT
*robot
;
5 ALLEGRO_BITMAP *robotGraphic
;
6 ALLEGRO_BITMAP *temp
;
7
8 ForeachLL_M
(listOfRobots, robot
)
9 {
10 temp
= al_create_bitmap(SHIELD_BMP_SZ, SHIELD_BMP_SZ
);
11
12 clearBitmap
(temp
);
13 clearBitmap
(robot->image
);
14
15 shieldCenterX
= al_get_bitmap_width(temp
) / 2; //All robot's shields are same size,
16 shieldCenterY
= al_get_bitmap_height(temp
) / 2; //so calculate center point here.
17
18 drawAngle
= 90 - robot->heading
; //Convert "math" angle to screen "heading"
19 if (drawAngle
< 0) //angle as rotate_sprite is in compass
20 drawAngle
= drawAngle
+ 360; //coords and make positive.
21 drawAngle
= drawAngle
* PI
/ 180; //Convert from degrees to radian.
22
23 modifier
= robot->shields
/ MAX_SHIELD_ENERGY
;
24
25 if (robot->graphic
!= NULL
){
26 robotGraphic
= robot->graphic
;
27 } else {
28 robotGraphic
= robotImg
;
29 }
30
31 al_set_target_bitmap(temp
);
32 al_draw_bitmap(robotGraphic,
33 al_get_bitmap_width(robot->image
) / 2
34 - al_get_bitmap_width(robotGraphic
) / 2,
35 al_get_bitmap_height(robot->image
) / 2
36 - al_get_bitmap_height(robotGraphic
) / 2,
0);
37 al_set_target_bitmap(robot->image
);
38 al_draw_rotated_bitmap(temp, shieldCenterX, shieldCenterY,
39 SHIELD_BMP_SZ
/ 2, SHIELD_BMP_SZ
/ 2, drawAngle,
0);
40 al_draw_tinted_bitmap(robot->shield,
41 al_map_rgba_f(1 * modifier,
1 * modifier,
1 * modifier,
42 modifier
),
0,
0,
0);
43 }
44
45 al_destroy_bitmap(temp
);
46}
And this is when I destroy the bitmap :
#SelectExpand
1void EndCompetition
() {
2 int i
;
3 ROBOT
*tempRobot,
*nextRobot
;
4 WEAPON
*tempWeapon,
*nextWeapon
;
5
6 //Move the dead robots back into the main list for deletion.
7 //deadRobotList should be empty after this loop has finished.
8 while (!IsEmptyLL
(deadRobotList
))
9 LinkAftLL
(LastElmLL
(robotList
), UnlinkLL
(FirstElmLL
(deadRobotList
)));
10
11 //Now iterate through each robot, cleaning up allocated memory
12 //and, when all memory is cleaned up, remove each one from the list.
13 SafeForeachLL_M
(robotList, tempRobot, nextRobot
)
14 //Has to be "safe" as
15 { //list elements will be
16 nextRobot
= NextElmLL
(tempRobot
); //deleted during the
17 for (i
= 0; i
< MAX_SENSORS
; i
++) //iteration.
18 if (tempRobot->sensorArray
[i
].image
!= NULL
)
19 al_destroy_bitmap(tempRobot->sensorArray
[i
].image
); //Free sensor images.
20
21 if (tempRobot->graphic
!= NULL
)
22 al_destroy_bitmap(tempRobot->graphic
); //Free custom images.
23 al_destroy_bitmap(tempRobot->image
); //Free robot bitmaps.
24 free(tempRobot->name
); //Free robot name strings.
25
26 DestLL
(tempRobot->mailBox
); //Remove all messages.
27
28 DelElmLL
(tempRobot
); //Delete the robot from the list.
29 }
30
31 //Now clean up the weapon list, deleting each weapon.
32 SafeForeachLL_M
(weaponList, tempWeapon, nextWeapon
)
33 {
34 nextWeapon
= NextElmLL
(tempWeapon
);
35 if (tempWeapon->image
!= NULL
)
36 al_destroy_bitmap(tempWeapon->image
); //Free weapon images.
37 DelElmLL
(tempWeapon
); //Delete the weapon.
38 }
39
40 if (IsEmptyLL
(robotList
) && IsEmptyLL
(deadRobotList
)
41 && IsEmptyLL
(weaponList
)) {
42 DestLL
(robotList
);
43 DestLL
(deadRobotList
);
44 DestLL
(weaponList
);
45 } else {
46 DestLL
(robotList
);
47 DestLL
(deadRobotList
);
48 DestLL
(weaponList
);
49 AbortOnError
(
50 "EndCompetition() discovered one of the main linked lists was "
51 "not empty before deletion.\n"
52 "Program will now end.");
53 }
54
55 //Delete the sounds.
56 for (i
= 0; i
< NUM_SOUNDS
; i
++)
57 if (theGame.sounds
[i
] != NULL
)
58 al_destroy_sample(theGame.sounds
[i
]);
59
60 DeInitGraphics
();
61
62}
The bitmap is destroyed at line 21-22th line.
Those are the only action I take on the robot.graphic.
Finally here is the action order of my game loop :
#SelectExpand
1void Fight
(ALLEGRO_DISPLAY *display
) {
2
3 calcsUntilOrders
++;
4
5 UpdateEnergySystems
(robotList
); //Do first so we know what
6 //systems are powered.
7
8 MoveRobots
(robotList
);
9 DrawRobotBitmaps
(robotList
);
10 CheckRobotCollisions
(&theGame, robotList
);
11
12 MoveWeapons
(weaponList
);
13 CheckWeaponCollisions
(&theGame, robotList, weaponList
);
14
15 //Now that collisions are
16 ApplyDamage
(&theGame, robotList, deadRobotList
); //done and weapons have
17 //hit, we apply damage.
18
19 DrawSensorBitmaps
(robotList
); //Need to draw BEFORE data is
20 //updated because bimaps are
21 //used in collision detection.
22 UpdateSensorData
(robotList
);
23
24 UpdateParticles
();
25
26 calcsCompleted
++;
27
28 if (calcsUntilOrders
== ORDER_FREQ
) {
29 calcsUntilOrders
= 0;
30 ForeachLL_M
(robotList, curRobot
)
31 curRobot->ActionsFunction
(TURN_TIME
);
32 }
33
34// if (theGame.useSounds)
35// PlaySounds(&theGame);
36
37}
@Edgar Reynaldo
I don't know because all the robot are managed the same way and the artefact are random. They don't appear on random frame they just show up randomly on a robot graphic . Plus I don't destroy the robot.graphic until the end of the game.
The fact that if I load the bitmap using a path in the RegisterRobot or using NULL to load the same bitmap doesn't give me the same result feel strange to me.