/* goblins - C# version converted from Java 10/2003 3d boxworld added 10/2004, directSound added 10/2005 Program skeleton by Chuck Liang, Hofstra University. Academic use only. This program needs to be compiled with "csc /r:boxworld.dll goblins.cs". */ using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; /* the only methods you must change here are init() and mainloop() */ public class goblins : System.Windows.Forms.Form { // 3d components - the y coordinate will be modeled by the // z coordinate in the boxworld. The boxworld y coordinate // is basically constant - since the playground is 2d. private System.ComponentModel.Container components = null; public static int XBOUND = 1024; // imaginary 3d dimensions public static int YBOUND = 768; // imaginary 3d dimensions public static int BOXHEIGHT = 600; // actual y coordinate in boxworld public static int Wwidth = 1070; // screen window dimensions public static int Wheight = 707; // some trial and error used :-) public static int LEVEL = 30; // height of playground grid public static Color Gridcolor = Color.Green; public static int Gridgap = 16; public static Color Wallcolor = Color.Yellow; public static double zoomratio = 0.5; public static double shortratio = 0.8; public static int tiltangle = 290; // initial view angle public int STEP = 4; // default speed increment public int FDELAY = 40; // animation frame delay public static boxworld playground; private Bitmap dbuffer; // double buffer private Graphics displaydc; // for screen private Graphics bufferdc; // for double buffer private Bitmap sbg; // static background private Graphics sbgdc; public SolidBrush brush = new SolidBrush( Color.Black ); // bk color public Pen pen = new Pen( Color.Green ); public static bool stop = false; private human professor; // constructor public goblins() { // setup 3d boxworld - this is a completely modular component playground = new boxworld(XBOUND,BOXHEIGHT,YBOUND,zoomratio,tiltangle,shortratio); components = new System.ComponentModel.Container(); this.Size = new System.Drawing.Size(Wwidth,Wheight); this.Name = "goblinapp"; this.Text = "Professor versus the Goblins"; this.BackColor = Color.Black; this.Load += new System.EventHandler(init); this.KeyDown +=new KeyEventHandler(handlekeys); // "delegate" } public void init(object o, System.EventArgs e) { // Graphics and Animation setup displaydc = this.CreateGraphics(); // device context for drawing dbuffer = new Bitmap(Wwidth,Wheight); // off-screen drawing buffer bufferdc = Graphics.FromImage(dbuffer); sbg = new Bitmap(Wwidth,Wheight); // static background buffer sbgdc = Graphics.FromImage(sbg); sbgdc.FillRectangle(brush,0,0,Wwidth,Wheight); // clear background // Draw static background grid; for(int i=0;i<=YBOUND;i+=Gridgap) playground.drawline(sbgdc,0,LEVEL,i,XBOUND-1,LEVEL,i,Gridcolor); for(int i=0;i<=XBOUND;i+=Gridgap) playground.drawline(sbgdc,i,LEVEL,0,i,LEVEL,YBOUND-1,Gridcolor); bufferdc.DrawImage(sbg,0,0,Wwidth,Wheight); // draw bkgrd to buffer // creat player object *************************** professor = new human(XBOUND-50,50,bufferdc,"man15.gif",25); } // end method init protected override void OnPaintBackground(PaintEventArgs pe) {} // don't autopaint (control animation manually) [STAThread] static void Main() { goblins theapp = new goblins(); Application.Run(theapp); } // This function is called asynchronously when a key is pressed: private void handlekeys(object sender, KeyEventArgs ke) { ke.Handled = true; switch(ke.KeyCode) { case Keys.Left: professor.setdirection(-1*STEP,0); break; case Keys.Right: professor.setdirection(STEP,0); break; case Keys.Up: professor.setdirection(0,1*STEP); break; case Keys.Down: professor.setdirection(0,-1*STEP); break; case Keys.Space: professor.setdirection(0,0); break; // stop case Keys.PageUp: STEP++; break; // speedup/slowdown case Keys.PageDown: STEP--; break; // won't take effect immediately default: break; } // switch } protected override void OnPaint(PaintEventArgs paintEvent ) { mainloop(); } /* utility function you might need: (distance between two coordinates) */ public static double dist(int x1, int y1, int x2, int y2) { int dx = (x1-x2) * (x1-x2); int dy = (y1-y2) * (y1-y2); return Math.Sqrt(dx+dy); } /* ------------mainloop controls how the game is played--------------- */ private void mainloop() { if (!stop) { professor.move(); // move should call draw automatically // don't touch the following, and make sure all your "moves" are above displaydc.DrawImage(dbuffer,0,0); // displays one animation frame System.Threading.Thread.Sleep(FDELAY); // delay between frames (ms) bufferdc.DrawImage(sbg,0,0,Wwidth,Wheight); // reset background Invalidate(); // tail-recursive call to OnPaint } // !stop /* display a message when done, such as: displaydc.DrawString("The Professor Wins!", new Font("Serif",28), new SolidBrush(Color.Red), (XBOUND/2)-135,(YBOUND/2)-30); */ } // mainloop // remember - any vars declared in mainloop are local - if you // want vars to maintain their values between "mainloop" calls, // you need to declare parameters or vars outside the method. // Clear commenting is required. /* ------------------------------------------------------------- */ } // end class goblins /* --- You have to modify the code below by using inheritance --- Do NOT call the base class "human" - make a generic base class such as "movingobject" and make human, goblin, etc... inherit from it. You are also required to define an INTERFACE in addition to the base class. ------------------------------------------------------------- */ public class human { private Image img; // animated gif private int xcord, ycord; // coordinates of center of gif private int dx, dy; // movement vector int radius; // size - also used to detect collision private Graphics dc; // private static int XBOUND = goblins.XBOUND; private static int YBOUND = goblins.YBOUND; private static int LEVEL = goblins.LEVEL; private static boxworld playground = goblins.playground; // For animation control of gifs // ... this took me a LONG time to figure out! private System.Drawing.Imaging.FrameDimension fdim; private int framecount; private int frame; // current frame // C# "properties": when you say object.X, you are calling the "get" code, // and when you say object.X = 2, you are calling the "set code". public int X { get { return xcord; } } public int Y { get { return ycord; } } public int R { get { return radius; } } public int DX { get { return dx; } set { dx = value; } // value is a keyword in C# } public int DY { get { return dy; } set { dy = value; } // value is whatever you're trying to assign to DY } public human(int x0, int y0,Graphics b0,string gif,int r0) // constructor { xcord = x0; ycord = y0; img = Image.FromFile(gif); // load animated gif file radius = r0; dc = b0; // divice context in Windows GDI+ allows drawing dx = dy = 0; // initial movement vector (stopped) // set info for number of animation dimension and frames in gif: Guid[] fdlist = img.FrameDimensionsList; fdim = new System.Drawing.Imaging.FrameDimension(fdlist[0]); framecount = img.GetFrameCount(fdim); // assume only 1 dimension frame = 0; } // constructor public void draw() // you shouldn't have to touch this unless you { // want to use different gifs (as when prof explodes) img.SelectActiveFrame(fdim,frame/2); // change frames at 1/2 speed frame = (frame + 1) % (2*framecount); // advance to next frame int r2 = (int) playground.dscale(radius,ycord); playground.drawimage(dc,img,xcord-r2,LEVEL-r2,ycord,radius*2,radius*2); //playground.drawcircle(dc,xcord,LEVEL,ycord,radius,Color.Red); } public void setdirection(int newdx, int newdy) { dx = newdx; dy = newdy; } /*** ---------------------------------------------------------- ***/ // My default move function will cause position of object to wrap around // the grid. You will have to override this method for the different // subclasses. For example, to make an object bounce off the edges instead // of wrapping around, reverse the sign of the dx value (dx *= -1) when // the object reaches the left/right edge, and reverse the dy value when // it reaches the top or bottom. // Also, note that the coordinate system is as you learned in math classes: // the lower left corner of the grid has coordinate(0,0) - the y coordinate // increases as you go upwards (or further away). public void move() { xcord = xcord + dx; // this line should always be part of move() if (xcord < radius/2) xcord = XBOUND-(radius/2); if (xcord > XBOUND-(radius/2)) xcord = radius/2; ycord = ycord + dy; // ... as is this line if (ycord < radius/2) ycord = YBOUND-(radius/2); if (ycord > YBOUND-(radius/2)) ycord = radius/2; draw(); } } // end class human