public void SetBallOnLoc(EPoint a_pnt, Ball a_ball) { if (a_pnt.X < 0 || a_pnt.X >= GridSize.Width || a_pnt.Y < 0) { return; } m_aGrid[a_pnt.X, a_pnt.Y] = a_ball; a_ball.GridLoc = a_pnt; a_ball.Loc = GetGfxLocFromGridLoc(a_pnt); ResetChainNums(); m_nCurrentChainNum = 0; ArrayList aSameColor = CalcColorChain(a_pnt); if (aSameColor.Count > 2) { ArrayList aAllRemove = new ArrayList(); //remove balls in color chain, and then all balls that are no longer connected to ceiling! //first color chain, and also find all neighbours to the color chain ArrayList aAllNeighbours = new ArrayList(); //make a list of all neighbours: foreach (Ball removeball in aSameColor) { ArrayList aNeighbours = GetNeighbours(removeball); foreach (Ball neighbour in aNeighbours) { if (aAllNeighbours.Contains(neighbour) == false && aSameColor.Contains(neighbour) == false) { aAllNeighbours.Add(neighbour); } } RemoveBallAtLoc(removeball.GridLoc); removeball.Burst(); //aAllRemove.Add(removeball); } ResetChainNums(); m_nCurrentChainNum = 0; //now for each neighbour, add to remove list if not connected to ceiling: foreach (Ball ball in aAllNeighbours) { //if one of these balls is connected to another, the recursive function will already have added it to its remove list if (ball.ChainNum < 0) { EndogineHub.Put("New chain"); m_aCurrentChainInfo = new ChainInfo(); if (RecursiveCalcConnection(ball) == false) //the chain is not connected to ceiling { foreach (Ball removeball in m_aCurrentChainInfo.Balls) { aAllRemove.Add(removeball); RemoveBallAtLoc(removeball.GridLoc); } } } } foreach (Ball removeball in aAllRemove) { removeball.Fall(); //Dispose(); //.Color = Color.FromArgb(100,100,100); } m_playArea.RemovedBalls(aSameColor.Count, aAllRemove.Count); } }
/// <summary> /// /// </summary> /// <param name="a_loc">start loc</param> /// <param name="a_vel">find first collision/bounce while moving this amount</param> /// <param name="pntGridStick"></param> /// <returns>true if it hit something to stick to (another ball, or ceiling)</returns> public bool GetFirstStickOrBounce(ref EPointF a_loc, ref EPointF a_vel, out EPoint pntGridStick, out EPointF pntBounce, bool bMoveBallAfterCollision) { EPointF pntCollision = new EPointF(0, 0); EPointF pntCircleAtCollision; EPointF pntNormal = new EPointF(0, 0); bool bCollided = false; pntGridStick = null; //new EPoint(0,0); pntBounce = null; //new EPointF(0,0); float fFirstTime = 1000; ArrayList aBalls = m_playArea.Grid.GetAllBalls(); foreach (Ball ball in aBalls) { float fTime; EPointF pntThisCollision; if (Endogine.Collision.Collision.CalcFirstCircleCircleCollisions( a_loc, ball.Loc, a_vel, new EPointF(0, 0), m_playArea.Grid.BallDiameter / 2 - 1, m_playArea.Grid.BallDiameter / 2 - 1, //it's more like the original if we subtract 1 out pntThisCollision, out fTime)) { if (fTime < fFirstTime) { pntCollision = pntThisCollision; fFirstTime = fTime; } } } if (fFirstTime < 1000) { EPointF pntfGrid = m_playArea.Grid.GetGridLocFromGfxLoc(pntCollision); pntGridStick = m_playArea.Grid.RoundToClosestGridLoc(pntfGrid); a_loc = m_playArea.Grid.GetGfxLocFromGridLoc(pntGridStick); a_vel = new EPointF(0, 0); return(true); } //check wall bounces and ceiling stick for (int nLineNum = 0; nLineNum < m_playArea.m_aCollisionLines.Count; nLineNum++) { ERectangleF rctLine = (ERectangleF)m_playArea.m_aCollisionLines[nLineNum]; if (Endogine.Collision.Collision.CalcCircleLineCollision(a_loc, m_playArea.Grid.BallDiameter / 2, a_vel, rctLine, out pntCollision, out pntCircleAtCollision)) { if (nLineNum == 0) { //hit ceiling: make it stick! EPointF pntfGrid = m_playArea.Grid.GetGridLocFromGfxLoc(pntCollision); EndogineHub.Put(pntCollision.ToString() + " " + pntfGrid.ToString()); pntGridStick = m_playArea.Grid.RoundToClosestGridLoc(pntfGrid); a_loc = m_playArea.Grid.GetGfxLocFromGridLoc(pntGridStick); a_vel.X = 0; a_vel.Y = 0; return(true); } //TODO: check all lines, and use the one that is collided with first. //Then a new test should be done from the bounce point pntBounce = pntCollision; //bounce against a wall: which direction will it have afterwards double dNormal = Endogine.Collision.Collision.GetNormalAngle(rctLine); //the line's direction, it shouldn't matter if it's up or down, or left or right - same bounce regardless if (dNormal >= Math.PI) { dNormal -= Math.PI; } if (dNormal >= Math.PI / 2) { dNormal -= Math.PI / 2; } double dVelAngle = Math.Atan2(a_vel.X, -a_vel.Y); double dAfterBounceAngle = dNormal - (dVelAngle - dNormal); //just so it's easier to debug: if (dAfterBounceAngle > Math.PI) { dAfterBounceAngle -= Math.PI; } //how far can it move before hitting wall EPointF pntBefore = new EPointF(pntCircleAtCollision.X - a_loc.X, pntCircleAtCollision.Y - a_loc.Y); double dPartOfMove = Endogine.Collision.PointLine.PointIsWhereOnLine(pntBefore, new ERectangleF(0, 0, a_vel.X, a_vel.Y)); if (dPartOfMove > 0.99) { dPartOfMove = 0.99; } else if (dPartOfMove < 0 && dPartOfMove > -0.001) { dPartOfMove = 0; } //the rest of the movement will be in bounce direction a_vel = EPointF.FromLengthAndAngle(a_vel.Length, (float)dAfterBounceAngle); //EPointF velNew = EPointF.FromLengthAndAngle(a_vel.Length, (float)dAfterBounceAngle); //a_vel.X = velNew.X; //a_vel.Y = velNew.Y; //TODO: pntCircleAtCollision is not correctly calculated. a_loc = pntCircleAtCollision; if (bMoveBallAfterCollision) { a_loc.X += a_vel.X * (float)(1.0 - dPartOfMove); a_loc.Y += a_vel.Y * (float)(1.0 - dPartOfMove); } bCollided = true; break; } } if (!bCollided) { a_loc.X += a_vel.X; a_loc.Y += a_vel.Y; } return(false); }
public static XmlNode Serialize(object a_obj, XmlNode a_node, string a_name) { System.Type type = a_obj.GetType(); System.Reflection.PropertyInfo[] propInfos = type.GetProperties(); if (a_name == null) { a_name = "GNode"; } XmlElement elm = a_node.OwnerDocument.CreateElement(a_name); //type.Name); XmlAttribute attrib; attrib = a_node.OwnerDocument.CreateAttribute("Assembly", null); attrib.InnerText = "Endogine"; //TODO: type.Assembly.AssemblyQualifiedName (=GetName()) elm.Attributes.Append(attrib); //TODO: we should optionally be able to specify which base class to serialize. //For example, we might want to serialize all different sprite-based objects as sprites, //not as Players, Balls, Ships etc... attrib = a_node.OwnerDocument.CreateAttribute("Type", null); attrib.InnerText = type.FullName; elm.Attributes.Append(attrib); a_node.AppendChild(elm); foreach (System.Reflection.PropertyInfo propInfo in propInfos) { if (propInfo.PropertyType.IsSerializable && //!propInfo.PropertyType.IsArray && propInfo.CanRead && propInfo.CanWrite && propInfo.PropertyType.IsPublic) { object propValue = null; try { propValue = propInfo.GetValue(a_obj, null); } catch { EndogineHub.Put(propInfo.Name + " failed"); continue; } if (propValue == null) { continue; } object[] attribs; // attribs = propInfo.GetCustomAttributes(typeof(BrowsableAttribute), true); // if (attribs.Length > 0) // { // BrowsableAttribute propAttrib = (BrowsableAttribute)attribs[0]; // if (propAttrib.Browsable == false) // continue; // } attribs = propInfo.GetCustomAttributes(typeof(DesignerSerializationVisibilityAttribute), true); if (attribs.Length > 0) { DesignerSerializationVisibilityAttribute propAttrib = (DesignerSerializationVisibilityAttribute)attribs[0]; if (propAttrib.Visibility == DesignerSerializationVisibility.Hidden) { continue; } } // //don't serialize if default value: attribs = propInfo.GetCustomAttributes(typeof(DefaultValueAttribute), true); if (attribs.Length > 0) { DefaultValueAttribute propAttrib = (DefaultValueAttribute)attribs[0]; if (propAttrib.Value.Equals(propValue)) { continue; } } if (propInfo.PropertyType.IsValueType == false && propInfo.PropertyType.IsSerializable && propInfo.PropertyType.UnderlyingSystemType != typeof(string)) { Serialize(propValue, elm, propInfo.Name); } else { string sVal = Convert.ToString(propValue); System.Xml.XmlElement prop = a_node.OwnerDocument.CreateElement(propInfo.Name); prop.SetAttribute("v", null, sVal); elm.AppendChild(prop); } } } return(elm); }
private void dataGrid1_CurrentCellChanged(object sender, System.EventArgs e) { ArrayList aVisibleNodes = TreeViewHelper.GetFlatVisibleTreeNodes(treeView1); int nNumVisible = aVisibleNodes.Count; //TODO: ugly way to stop the extra line in dataview (for adding new rows) from being available: int nCurrRow = dataGrid1.CurrentCell.RowNumber; if (nCurrRow >= nNumVisible) { //dataGrid1.Select(nCurrRow-1); dataGrid1.CurrentRowIndex = nCurrRow - 1; } else { dataGrid1.ReadOnly = false; } if (m_pntLastDataGridCell.X >= 0) { string sVal = Convert.ToString(((DataTable)dataGrid1.DataSource).Rows[m_pntLastDataGridCell.Y][m_pntLastDataGridCell.X]); TreeNode treeNode = (TreeNode)aVisibleNodes[m_pntLastDataGridCell.Y]; XmlNode xmlNode = (XmlNode)treeNode.Tag; if (m_pntLastDataGridCell.X == 0) { string sForXMLParse = "<temp " + sVal + "/>"; XmlDocument xmlDoc = new XmlDocument(); try { xmlDoc.LoadXml(sForXMLParse); xmlNode.Attributes.RemoveAll(); foreach (XmlAttribute attrib in xmlDoc.ChildNodes[0].Attributes) { XmlAttribute newAttrib = (XmlAttribute)m_doc.CreateNode(XmlNodeType.Attribute, attrib.Name, null); newAttrib.InnerText = attrib.InnerText; xmlNode.Attributes.Append(newAttrib); } } catch { ((DataTable)dataGrid1.DataSource).Rows[m_pntLastDataGridCell.Y][m_pntLastDataGridCell.X] = CreateAttributesString(xmlNode); //MessageBox.Show("Attributes formatting invalid"); } EndogineHub.Put(sVal); } else if (m_pntLastDataGridCell.X == 1) { bool bFound = false; foreach (XmlNode childNode in xmlNode.ChildNodes) { if (childNode.NodeType == XmlNodeType.Text) { childNode.InnerText = sVal; bFound = true; break; } } if (!bFound) { XmlNode newNode = m_doc.CreateTextNode(sVal); xmlNode.AppendChild(newNode); } } } m_pntLastDataGridCell.Y = dataGrid1.CurrentRowIndex; m_pntLastDataGridCell.X = dataGrid1.CurrentCell.ColumnNumber; }