600 likes | 620 Views
Learn how to develop a tank game using OOP method & physics equations to create engaging gameplay. Understand the system of coordinates, boundaries, transformation & effects in a game world. Explore the movement mechanics for tanks, aliens, bullets, clouds & more. Study how to manage object instances, collision detection, and synchronization between tank and bullet movements. Discover methods to calculate launching angles, velocities, and trajectories for in-game projectiles. Practice coding classes, functions, and design strategies for an interactive gaming experience.
E N D
159.234LECTURE 10 Developing the Tank Game • Assignment #1 • Game Structure • Drawing the Tank • Firing the bullet • Keyboard, mouse • Zoom-in, zoom-out
Objects in the Game Why develop this game? The game is too complex to be written using just the traditional structured approach. OOP is the most practical approach in writing this game. Tank Alien Clouds Bullet Ledge We would want to develop the game by writing classes, and creating instances of them to enable us to keep track of each object’s property isolated from the others.
System of Coordinates +y 0 +x World System of Coordinates Tank, Alien & Clouds movement follow this system of coordinates. To move upwards: + DispY To move downwards: - DispY To move to the right: + DispX To move to the left: - DispX Disp – stands for Displacement All Physics equations work with this system of coordinates.
System of Coordinates +y 0 +x To respond to Left/Right movement commands from the user, simple statements such as the following would suffice: Left: if(Boundary checking here…) TankX –= 2; Right: if(Boundary checking here…) TankX += 2; EARTH_Y: For example: 100
System of Coordinates +y 0 +x The Bullet object is plotted using Physics equations and transformation Equations. TransformationX(PhysicsX(t,..)) t – dictates the next position of the bullet.
159.234 WORLD-to-DEVICE COORDINATES 100,000,000 miles x 500,000 miles Transformation Equations 1280 x 1024 pixels +y 0 +x (Xworld,Yworld) (XDevice,YDevice) +x +y 0 World System of Coordinates Device System of Coordinates
159.234 SETTING THE BOUNDARIES Use the upper-left and bottom-right coordinates to set the boundaries World Boundaries +y 0 +x (Xworld,Yworld) (XDevice,YDevice) +x +y 0 Top-left: x1, y1 Bottom-right: x2, y2
159.234 Setting the World Boundaries x1=0 y1 = maximum_height x2 = maximum_range y2 = 0 (x1, y1) Projectile Motion +y (Xworld,Yworld) ground +x 0 (x2, y2)
159.234 EFFECTS OF CHANGING THE BOUNDARIES System of Coordinates What happens if we double all the maximum values for the WorldBound Coordinates? What happens if we decrease the maximum values for the WorldBound Coordinates?
159.234 SETTING THE BOUNDARIES World Boundaries where =85 degrees where =45 degrees Time of flight : from take-off to landing
159.234 TRANSFORMATION EQUATIONS World-to-Device Coordinates Computed using the Physics equation for x
159.234 PHYSICS EQUATIONS Increment t in the equations and x and y will be automatically adjusted. Projectile Motion where g = 9.8 m/sec.2pull of gravity Voinm/sec.initial velocity tinsec.Time in radians Launching Angle
159.234 Unit Conversion for Theta (degrees-to-radians) Projectile Motion = Theta_in_degrees * M_PI/180 Defined in math.h e.g. cos(), sin()
159.234 PUTTING THE PIECES TOGETHER circle(x, y, radius) // InitGraphics here // InitBoundaries here t=0.0; while(t < tf) { cleardevice(); setcolor(RED); circle (Xdev( x(t, Vo, Theta) ), Ydev( y(t, Vo, Theta)), 12); t=t+tinc; } Projectile Motion World-to-Device Transformation Function Physics Equation for x
Bullet Converting the code into its object-oriented representation: class Bullet { public: private }; Physics Equations Transformation Equations Drawing the Bullet Moving the Bullet Checking for Collision – can be handled outside the Bullet class, but this will depend on your class design. P The codes that make the Tank move will have to be assembled together inside a function, rather than being dispersed inside a while loop (as seen earlier).
Bullet Converting the code into its object-oriented representation: class Bullet { public: private }; Physics Equations Transformation Equations Drawing the Bullet Moving the Bullet Checking for Collision Q How to synchronize the movement of the tank and the bullet? How to make the bullet follow the path of a trajectory moving to the right/left? Q Q What controls the speed of the bullet animation?
Bullet & Tank The bullet should be released where the Tank’s nozzle points to, and follow the appropriate trajectory (whether to move to the left, or right). How can this be done?
Releasing the bullet CASES TO CONSIDER Note: the tank’s nozzle can be directed by the user to any angle (e.g. [0, 170])
Setting the boundaries for the Bullet A • Next, set the bullet’s world components (x, y) to point to the • location of the tank’s nozzle. x = tankNozzleX; y = tankNozzleY; The time of flight will have to be calculated using the formula that considers a Target lower than the launch point.
Class Tank You should monitor the current Vo and Theta set by the user for the Tank, and pass these parameters to the Bullet class prior to releasing the bullet. Launching Angle of Bullet = Theta from Tank Vo = Vo from Tank
Class Tank Tank’s Nozzle Angle vs. Bullet’s Launching Angle • Initially, • NozzleAngle = Angle as defined by user – 90; //45-90 • Theta = Angle as defined by user; //45 • Next, every time the Tank’s NozzleAngle is changed (through user • keyboard interaction), we perform the following updates: • To move the NozzleAnglein a clock-wise direction: • NozzleAngle = NozzleAngle +2 • Theta = Theta -2 • To move the NozzleAnglein a counter clock-wise direction: • NozzleAngle = NozzleAngle -2 • Theta = Theta +2
Class Tank NozzleAngle = Angle NozzleLength = 25 //some constant value (NozzleX, NozzleY) (Tx,Ty) Angle from user (e.g. 45 degrees) NozzleX = Tx + NozzleLength*cos((NozzleAngle) * M_PI / 180.0) NozzleY = Ty + NozzleLength*sin((NozzleAngle) * M_PI / 180.0) Take note: The Nozzle position is calculated relative to the Tank’s body. Therefore, when the tank’s body moves at some angle, the nozzle moves as well.
Class Tank Tank during take-off When in-flight Nozzle moves with the Tank’s body! Making the Tank to appear to be inclined would require some trigonometric formulas.
Class Tank For easier handling, you may want to compute all the coordinates of the tank figure based on just a single point in the Tank (e.g. TankX, TankY). Top-right Top-left bottom-right bottom-left (TankX,TankY) In so doing, only TankX and TankY needs to be updated every time the user instructs the tank to move via keyboard control. The rest of the other coordinates can be calculated relative to this point.
Facing to the Right Top-right Top-left bottom-right bottom-left (TankX,TankY) Top-right X = TankX+W*cos((Angle)*M_PI/180)); e.g. Angle=5 Top-right Y = TankY+H+W*sin((Angle)*M_PI/180)); //top-right tankBody[2]=Xdev(WBound,DBound,(tankX+W*cos((angle) * M_PI / 180.0))); tankBody[3]=Ydev(WBound,DBound,(tankY+H+W*sin((angle) * M_PI / 180.0)));
Facing to the Right Top-right Top-left bottom-right bottom-left (TankX,TankY) Bottom-right X = TankX+W*cos((Angle)*M_PI/180)) + (H*sin(Angle*M_PI/180)); e.g. Angle=5 Bottom-right Y = TankY+W*sin((Angle)*M_PI/180)); //bottom-right tankBody[4]=Xdev(WBound,DBound,(tankX+W*cos((angle) * M_PI / 180.0)) + (H*sin(angle*M_PI/180.0))); tankBody[5]=Ydev(WBound,DBound,(tankY+W*sin((angle) * M_PI / 180.0)));
Facing to the Right Top-right Top-left bottom-right bottom-left (TankX,TankY) Top-left X = TankX; Top-left Y = TankY+H; tankBody[0]=Xdev(WBound,DBound,tankX); tankBody[1]=Ydev(WBound,DBound,tankY+H);
Facing to the Right Top-right Top-left bottom-right bottom-left (TankX,TankY) Bottom-left X = TankX + (H*sin(Angle*M_PI/180)); e.g. Angle=5 Bottom-left Y = TankY; //bottom-left tankBody[6]=Xdev(WBound,DBound,tankX+(H*sin(angle * M_PI/180.0))); tankBody[7]=Ydev(WBound,DBound,tankY);
Facing to the Left Top-left Top-right bottom-left bottom-right (TankX,TankY)
Facing to the Left Top-left Top-right bottom-left bottom-right (TankX,TankY)
Facing to the Left Top-left Top-right bottom-left bottom-right (TankX,TankY)
Facing to the Left Top-left Top-right bottom-left bottom-right (TankX,TankY)
159.234 void fillpoly (int numpoints, int *polypoints); Fillpoly • fillpoly draws the outline of a polygon with numpointspoints in the current line style and color (just as drawpoly does), then fills the polygon using the current fill pattern and fill color. polypointspoints to a sequence of (numpoints * 2) integers. Each pair of integers gives the x- and y-coordinates of a point on the polygon.
159.234 void fillpoly (int numpoints, int *polypoints); float W=35, H=15; int tankBody[8]; //top-left tankBody[0]=Xdev(tankX); tankBody[1]=Ydev(tankY+H); //top-right tankBody[2]=Xdev((tankX+W*cos((angle) * M_PI / 180.0))); tankBody[3]=Ydev((tankY+H+W*sin((angle) * M_PI / 180.0))); //bottom-right tankBody[4]=Xdev((tankX+W*cos((angle) * M_PI / 180.0)) + (H*sin(angle*M_PI/180.0))); tankBody[5]=Ydev((tankY+W*sin((angle) * M_PI / 180.0))); //bottom-left tankBody[6]=Xdev(tankX+(H*sin(angle * M_PI/180.0))); tankBody[7]=Ydev(tankY); setcolor(YELLOW); setfillstyle(SOLID_FILL,RED); fillpoly(4,tankBody); Fillpoly Example
159.234 void pieslice (int x, int y, int stangle, int endangle, int radius); Pieslice • Use with setcolor() and setfillstyle() functions
void drawWheel(float x, float y, float r, int a, directionType xDir) { a = a % 360; setcolor(BLACK); circle(Xdev(x),Ydev(y),Xdev(r)); setfillstyle(SOLID_FILL,RED); setlinestyle(SOLID_LINE,0,1); pieslice(Xdev(x),Ydev(y),a,a+30,Xdev(r)); setfillstyle(SOLID_FILL,GREEN); pieslice(Xdev(x),Ydev(y),a+180,a+30+180,Xdev(r)); }
Keyboard Handling Monitoring the Control and Shift keys: bool ControlFlag, ShiftFlag; if(GetAsyncKeyState(VK_CONTROL)<0) { ControlFlag = ! ControlFlag; } if(GetAsyncKeyState(VK_SHIFT)<0) { ShiftFlag = ! ShiftFlag; } For the Tank to Jump to the Right: Control + Shift + Right Arrow key For the Tank to Jump to the Left: Control + Shift + Left Arrow key
Keyboard Handling Possible approach in monitoring key combinations : if(GetAsyncKeyState(VK_RIGHT)<0) { XDir=RIGHT; if(ShiftFlag) { outtext("SHIFT + RIGHT"); ShiftFlag=!ShiftFlag; } if(ControlFlag) { outtext("CTRL + RIGHT"); if (TankX < getmaxx()-W) TankX += 2; Angle=Angle-5; RaiseWheelFlag=TRUE; ControlFlag=!ControlFlag; } …
159.234 rand() generates a pseudorandom number - returns int Element of Surprise srand(time(NULL)); int RandomVal(int min, int max) { return (min + (rand() % ((max-min)+1) )); }
159.234 srand() Seed for random-number generation Element of Surprise Seed the random-number generator with current time so that the numbers will be different every time we run. srand( (unsigned)time( NULL ) ); /* Display 10 numbers. */ for( i = 0; i < 10;i++ ) printf( " %6d\n", rand() );
159.234 rand() float RandomVal(float min, float max) { float r; r = (float)rand()/RAND_MAX; r = min + (r*(max-min)); return r; } Element of Surprise rand() returns a pseudo-random integral number in the range (0 to RAND_MAX)-1
159.234 clock() void wait ( int seconds ) { clock_tendwait; endwait = clock () + seconds * CLOCKS_PER_SEC ; while (clock() < endwait) {} } Time elapsed, wait… clock_tstartTime, elapsedTime; startTime = clock(); … ... elapsedTime = (clock() - startTime)/CLOCKS_PER_SEC;
From nozzle to ground t=0 from t=0 to TimeOfFlight T=TimeOfFlight While BulletY is less than EARTH_Y, let the bullet fall (t=t+tinc) EARTH_Y The changes would guarantee that the complete trajectory would be plotted on screen (from t=0 to TimeOfFlight). The only thing left would be to account for the motion of the projectile until it hits the ground (EARTH_Y).
From nozzle to ground (x1, y1) t=0 from t=0 to TimeOfFlight T=TimeOfFlight (x1, y1) The TimeOfFlight is computed only from the point of release to the same y location. However, we need to consider the case when the tank is on top of the ledge.
Jumping over the Ledge Safe landing zone (cx,cy) – tank’s center of gravity Check to see if the tank’s center position falls within the safe landing zone of the ledge.
Jumping over the Ledge Safe landing zone (cx,cy) – tank’s center of gravity Q But when can the tank possibly land on the ledge? When it is falling! It could have jumped off another ledge, or jumped from the ground. Flag variables will have to be created to monitor these cases.
Jumping over the Ledge Safe landing zone +Y (cx,cy) – tank’s center of gravity Q How do we know that the tank is falling? If its PrevY position is less than its CurrentY position, or If it’s (cx, cy) position goes out of the safe landing zone area (fell-off the ledge by accident!). Flag variables will have to be created to monitor these cases.
Jumping over the Ledge Safe landing zone +Y (cx,cy) – tank’s center of gravity Q When do we allow a Tank to jump? If it’s not on the air yet! If it’s currently on top of a ledge, or if it’s resting on the ground. Flag variables will have to be created to monitor these cases.