The Challenge: |---->Program a 2d tank application in the language of your choice that adheres to the following:
#-The tank must rotate using the left and right directional keys.
#-The tank must loosely resemble a tank.
#-The tank must move forward or backward respectively from the direction it is facing using the up and down directional keys.
#-Pressing spacebar must fire a 'shot' in the direction the tank is facing.
#-The perspective of the user must be fixed and facing down at the tank.
#-The tank, shot, and ground must each have their own color. (all shots may have the same color)
/* Copyright (c) 2010 Xarn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
Disclaimer: this code has many examples of "bad practices" because I was 100% focused on minimize coding time while meeting the requirements
import java.awt.*;
import java.applet.*;
import java.util.*;
import java.awt.event.*;
import java.awt.image.*;
public class a extends Applet implements Runnable,KeyListener{
double x,y;
double r,sdx,sdy;
boolean left,right,down,up;
double sx=-5,sy=-5;
int TANK_SIZE=20;
BufferedImage buf;
public void init(){
x=getWidth()/2;
y=getHeight()/2;
addKeyListener(this);
buf=new BufferedImage(getWidth(),getHeight(),BufferedImage.TYPE_3BYTE_BGR);
new Thread(this).start();
}
public void update(Graphics g){
paint(buf.getGraphics());
g.drawImage(buf, 0,0,null);
}
public void paint(Graphics g){
int[] xpoints=new int[8];
int[] ypoints=new int[8];
for(int i=0;i<4;i++){
xpoints[i]=(int)(x+TANK_SIZE*Math.cos(r+i*Math.PI/2));
ypoints[i]=(int)(y+TANK_SIZE*Math.sin(r+i*Math.PI/2));
}
xpoints[4]=(4*xpoints[0]+5*xpoints[3])/9;
ypoints[4]=(4*ypoints[0]+5*ypoints[3])/9;
xpoints[5]=(int)(x+1.5*TANK_SIZE*Math.cos(r-3*Math.PI/11));
ypoints[5]=(int)(y+1.5*TANK_SIZE*Math.sin(r-3*Math.PI/11));
xpoints[6]=(int)(x+1.5*TANK_SIZE*Math.cos(r-3*Math.PI/13));
ypoints[6]=(int)(y+1.5*TANK_SIZE*Math.sin(r-3*Math.PI/13));
xpoints[7]=(5*xpoints[0]+4*xpoints[3])/9;
ypoints[7]=(5*ypoints[0]+4*ypoints[3])/9;
g.setColor(Color.gray);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.green);
g.fillPolygon(xpoints,ypoints,8);
if(left)
r-=.1;
if(right)
r+=.1;
double dx=Math.cos(r-Math.PI/4);
double dy=Math.sin(r-Math.PI/4);
if(up){
x+=dx*10;
y+=dy*10;
}
if(down){
x-=dx*10;
y-=dy*10;
}
g.setColor(Color.yellow);
if(sx!=-5&&sy!=-5){
sx+=sdx;
sy+=sdy;
}
if(sx<-3||sx>getWidth()||sy<-3||sy>getWidth()){
sx=-5;
sy=-5;
}
g.fillOval((int)sx-1, (int)sy-1,3, 3);
}
public void run() {
while(true){
Graphics g=getGraphics();
if(g!=null)
update(getGraphics());
try{
Thread.sleep(30);
}catch(Exception e){}
}
}
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_UP:
up=true;
break;
case KeyEvent.VK_DOWN:
down=true;
break;
case KeyEvent.VK_LEFT:
left=true;
break;
case KeyEvent.VK_RIGHT:
right=true;
break;
case KeyEvent.VK_SPACE:
if(sx==-5&&sy==-5){
sx=x;
sy=y;
sdx=Math.cos(r-Math.PI/4)*20;
sdy=Math.sin(r-Math.PI/4)*20;
}
break;
}
}
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_UP:
up=false;
break;
case KeyEvent.VK_DOWN:
down=false;
break;
case KeyEvent.VK_LEFT:
left=false;
break;
case KeyEvent.VK_RIGHT:
right=false;
break;
}
}
public void keyTyped(KeyEvent e){}
}
>>16 #ifndef M_PI #define M_PI 3.14159265358979323846 #endif
This is unnecessary if you define _BSD_SOURCE or _XOPEN_SOURCE=500. The math.h man page doesn't tell you this for some reason, but M_PI isn't part of ANSI C, so compiling with -ansi undefines it (along with a bunch of other constants).
I initially thought glibc was being retarded, but it turns out it was just poor documentation.
Name:
Anonymous2010-05-14 20:05
>>22
It wasn't written for shortness or readability thus the disclaimer, 100% code time. Also the ugliest part is the tank drawing which the C version sidesteps by using images.
compared to the boilerplate needed for win32, opengl or directx to do the same? yes, no contest
Name:
Anonymous2010-05-14 22:17
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
static class Program
{
static void Main(string[] args)
{
using (TankGame game = new TankGame()) game.Run();
}
}
public class Entity
{
public Texture2D Texture;
public Vector2 Location;
public float Facing;
public float Velocity;
public Vector2 Origin { get { return new Vector2(this.Width / 2, this.Height / 2); } }
public int Height { get { return Texture.Height; } }
public int Width { get { return Texture.Width; } }
spriteBatch.Begin();
this.tank.Draw(this.spriteBatch);
foreach (Entity shot in shots) shot.Draw(this.spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
Name:
Anonymous2010-05-14 22:28
>>25
I can only assume you've never used a game programming or graphic library yourself.
You can even leave out END_OF_MAIN(), if you like. It's only there for the retarded platforms. It saves you the effort of having to write a WinMain by hand.
>>30
So why not do the same WinMain hack in Allegro that SDL is using? All they do is #define main to SDLmain or something, and link the "real" main in the library itself.
>>33
How many is enough? Engineers and physicists usually claim to need about 3-5. I need about 7. Almost no one needs as much as 12, but since it's a constant: why not?
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
//System.out.println("test ");
if ( key == KeyEvent.VK_UP )
up = true;
if ( key == KeyEvent.VK_LEFT )
left = true;
if ( key == KeyEvent.VK_DOWN )
down = true;
if ( key == KeyEvent.VK_RIGHT )
right = true;
repaint();
e.consume();
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
int i;
if ( key == KeyEvent.VK_UP )
up = false;
if ( key == KeyEvent.VK_LEFT )
left = false;
if ( key == KeyEvent.VK_DOWN )
down = false;
if ( key == KeyEvent.VK_RIGHT )
right = false;
if ( key == KeyEvent.VK_SPACE)
{
for(i = 0; i < 3; i++)
{
if(shots[i].active == false)
{
shots[i] = new burret(xpos, ypos, counter);
shots[i].active = true;
i = 3;
}
}
>>37
POSIX says that it "shall have type double and shall be accurate within the precision of the double type."
any compiler that isn't horribly broken will turn (4*atan(1)) into a constant at compile time, so there's really no reason not to use that.
>>47
That's cool and all but you just know that besides causing mass confusion among people who just can't stand it on principle, some shit at Google is going to throw a tantrum over it and advocate the removal of language features if you do something like that. I wish I was joking.
There is also the practical matter that not all FPUs are created equal, and you can end up with (even more) inaccurate values this way. I know it doesn't matter much when your FPU is in a bad way, I'm just saying that for every reason to use the function call, there are two equally insignificant reasons not to. Honestly the only really good reason I can think of not to is inertia.
Name:
Anonymous2010-05-15 4:10
There is also the practical matter that not all FPUs are created equal, and you can end up with (even more) inaccurate values this way.
If your FPU is that broken, you're screwed no matter what you do.