public override void OnFixedUpdate(float timeMult) { base.OnFixedUpdate(timeMult); if (frozenTimeLeft > 0) { return; } if (canJump) { if (MathF.Abs(speedX) > float.Epsilon && !CanMoveToPosition(speedX * 4, 0)) { SetTransition(AnimState.TransitionWithdraw, false, delegate { HandleTurn(true); }); isTurning = true; canHurtPlayer = false; speedX = 0; PlaySound("Withdraw", 0.4f); } } if (!isTurning && !isWithdrawn && !isAttacking) { AABB aabb = AABBInner + new Vector2(speedX * 32, 0); if (levelHandler.TileMap.IsTileEmpty(ref aabb, true)) { foreach (Player player in levelHandler.GetCollidingPlayers(aabb + new Vector2(speedX * 32, 0))) { if (!player.IsInvulnerable) { Attack(); break; } } } } }
private void DrawLayer(IDrawDevice device, ref TileMapLayer layer, int cacheIndex) { if (!layer.Visible) { return; } Vector2 viewSize = device.TargetSize; Vector3 viewCenter = device.ViewerPos; Point2 tileCount = new Point2(layer.LayoutWidth, layer.Layout.Length / layer.LayoutWidth); Vector2 tileSize = new Vector2(tileset.TileSize, tileset.TileSize); // Update offsets for moving layers if (MathF.Abs(layer.AutoSpeedX) > 0) { layer.OffsetX += layer.AutoSpeedX * Time.TimeMult; if (layer.RepeatX) { if (layer.AutoSpeedX > 0) { while (layer.OffsetX > (tileCount.X * 32)) { layer.OffsetX -= (tileCount.X * 32); } } else { while (layer.OffsetX < 0) { layer.OffsetX += (tileCount.X * 32); } } } } if (MathF.Abs(layer.AutoSpeedY) > 0) { layer.OffsetY += layer.AutoSpeedY * Time.TimeMult; if (layer.RepeatY) { if (layer.AutoSpeedY > 0) { while (layer.OffsetY > (tileCount.Y * 32)) { layer.OffsetY -= (tileCount.Y * 32); } } else { while (layer.OffsetY < 0) { layer.OffsetY += (tileCount.Y * 32); } } } } // Get current layer offsets and speeds float loX = layer.OffsetX; float loY = layer.OffsetY - (layer.UseInherentOffset ? (viewSize.Y - 200) / 2 : 0); // Find out coordinates for a tile from outside the boundaries from topleft corner of the screen float x1 = viewCenter.X - 70 - (viewSize.X * 0.5f); float y1 = viewCenter.Y - 70 - (viewSize.Y * 0.5f); if (layer.BackgroundStyle != BackgroundStyle.Plain && tileCount.Y == 8 && tileCount.X == 8) { const float PerspectiveSpeedX = 0.4f; const float PerspectiveSpeedY = 0.16f; RenderTexturedBackground(device, ref layer, cacheIndex, (x1 * PerspectiveSpeedX + loX), (y1 * PerspectiveSpeedY + loY)); } else { // Figure out the floating point offset from the calculated coordinates and the actual tile // corner coordinates float xt = TranslateCoordinate(x1, layer.SpeedX, loX, false, viewSize.Y, viewSize.X); float yt = TranslateCoordinate(y1, layer.SpeedY, loY, true, viewSize.Y, viewSize.X); float remX = xt % 32f; float remY = yt % 32f; // Calculate the index (on the layer map) of the first tile that needs to be drawn to the // position determined earlier int tileX, tileY, tileAbsX, tileAbsY; // Get the actual tile coords on the layer layout if (xt > 0) { tileAbsX = (int)Math.Floor(xt / 32f); tileX = tileAbsX % tileCount.X; } else { tileAbsX = (int)Math.Ceiling(xt / 32f); tileX = tileAbsX % tileCount.X; while (tileX < 0) { tileX += tileCount.X; } } if (yt > 0) { tileAbsY = (int)Math.Floor(yt / 32f); tileY = tileAbsY % tileCount.Y; } else { tileAbsY = (int)Math.Ceiling(yt / 32f); tileY = tileAbsY % tileCount.Y; while (tileY < 0) { tileY += tileCount.Y; } } // update x1 and y1 with the remainder so that we start at the tile boundary // minus 1 because indices are updated in the beginning of the loops x1 -= remX - 32f; y1 -= remY - 32f; // Save the tile Y at the left border so that we can roll back to it at the start of // every row iteration int tileYs = tileY; // Calculate the last coordinates we want to draw to float x3 = x1 + 100 + viewSize.X; float y3 = y1 + 100 + viewSize.Y; Material material = null; Texture texture = null; ColorRgba mainColor = ColorRgba.White; // Reserve the required space for vertex data in our locally cached buffer int neededVertices = (int)((((x3 - x1) / 32) + 1) * (((y3 - y1) / 32) + 1) * 4); if (cachedVertices == null || cachedVertices.Length < neededVertices) { cachedVertices = new VertexC1P3T2[neededVertices]; } int vertexIndex = 0; int tile_xo = -1; for (float x2 = x1; x2 < x3; x2 += 32) { tileX = (tileX + 1) % tileCount.X; tile_xo++; if (!layer.RepeatX) { // If the current tile isn't in the first iteration of the layer horizontally, don't draw this column if (tileAbsX + tile_xo + 1 < 0 || tileAbsX + tile_xo + 1 >= tileCount.X) { continue; } } tileY = tileYs; int tile_yo = -1; for (float y2 = y1; y2 < y3; y2 += 32) { tileY = (tileY + 1) % tileCount.Y; tile_yo++; LayerTile tile = layer.Layout[tileX + tileY * layer.LayoutWidth]; if (!layer.RepeatY) { // If the current tile isn't in the first iteration of the layer vertically, don't draw it if (tileAbsY + tile_yo + 1 < 0 || tileAbsY + tile_yo + 1 >= tileCount.Y) { continue; } } Point2 offset; bool isFlippedX, isFlippedY; if (tile.IsAnimated) { if (tile.TileID < animatedTiles.Count) { offset = animatedTiles[tile.TileID].CurrentTile.MaterialOffset; isFlippedX = (animatedTiles[tile.TileID].CurrentTile.IsFlippedX != tile.IsFlippedX); isFlippedY = (animatedTiles[tile.TileID].CurrentTile.IsFlippedY != tile.IsFlippedY); //mainColor.A = tile.MaterialAlpha; mainColor.A = animatedTiles[tile.TileID].CurrentTile.MaterialAlpha; } else { continue; } } else { offset = tile.MaterialOffset; isFlippedX = tile.IsFlippedX; isFlippedY = tile.IsFlippedY; mainColor.A = tile.MaterialAlpha; } if (material != tile.Material) { // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, cachedVertices, 0, vertexIndex); vertexIndex = 0; material = tile.Material.Res; texture = material.MainTexture.Res; } Rect uvRect = new Rect( offset.X * texture.UVRatio.X / texture.ContentWidth, offset.Y * texture.UVRatio.Y / texture.ContentHeight, tileset.TileSize * texture.UVRatio.X / texture.ContentWidth, tileset.TileSize * texture.UVRatio.Y / texture.ContentHeight ); // ToDo: Flip normal map somehow if (isFlippedX) { uvRect.X += uvRect.W; uvRect.W *= -1; } if (isFlippedY) { uvRect.Y += uvRect.H; uvRect.H *= -1; } Vector3 renderPos = new Vector3(x2, y2, layer.Depth); renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { renderPos.Y += 0.5f; } cachedVertices[vertexIndex + 0].Pos.X = renderPos.X; cachedVertices[vertexIndex + 0].Pos.Y = renderPos.Y; cachedVertices[vertexIndex + 0].Pos.Z = renderPos.Z; cachedVertices[vertexIndex + 0].TexCoord.X = uvRect.X; cachedVertices[vertexIndex + 0].TexCoord.Y = uvRect.Y; cachedVertices[vertexIndex + 0].Color = mainColor; cachedVertices[vertexIndex + 1].Pos.X = renderPos.X; cachedVertices[vertexIndex + 1].Pos.Y = renderPos.Y + tileSize.Y; cachedVertices[vertexIndex + 1].Pos.Z = renderPos.Z; cachedVertices[vertexIndex + 1].TexCoord.X = uvRect.X; cachedVertices[vertexIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H; cachedVertices[vertexIndex + 1].Color = mainColor; cachedVertices[vertexIndex + 2].Pos.X = renderPos.X + tileSize.X; cachedVertices[vertexIndex + 2].Pos.Y = renderPos.Y + tileSize.Y; cachedVertices[vertexIndex + 2].Pos.Z = renderPos.Z; cachedVertices[vertexIndex + 2].TexCoord.X = uvRect.X + uvRect.W; cachedVertices[vertexIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H; cachedVertices[vertexIndex + 2].Color = mainColor; cachedVertices[vertexIndex + 3].Pos.X = renderPos.X + tileSize.X; cachedVertices[vertexIndex + 3].Pos.Y = renderPos.Y; cachedVertices[vertexIndex + 3].Pos.Z = renderPos.Z; cachedVertices[vertexIndex + 3].TexCoord.X = uvRect.X + uvRect.W; cachedVertices[vertexIndex + 3].TexCoord.Y = uvRect.Y; cachedVertices[vertexIndex + 3].Color = mainColor; vertexIndex += 4; } } // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, cachedVertices, 0, vertexIndex); } }
protected virtual void OnFixedUpdate(float timeMult) { if (currentCarryOver.HasValue) { bool playersReady = true; foreach (Player player in players) { // Exit type is already provided playersReady &= player.OnLevelChanging(ExitType.None); } if (playersReady) { if (levelChangeTimer > 0) { levelChangeTimer -= timeMult; } else { root.ChangeLevel(currentCarryOver.Value); currentCarryOver = null; initState = InitState.Disposed; return; } } } if (difficulty != GameDifficulty.Multiplayer) { if (players.Count > 0) { Vector3 pos = players[0].Transform.Pos; int tx1 = (int)pos.X >> 5; int ty1 = (int)pos.Y >> 5; int tx2 = tx1; int ty2 = ty1; #if ENABLE_SPLITSCREEN for (int i = 1; i < players.Count; i++) { Vector3 pos2 = players[i].Transform.Pos; int tx = (int)pos2.X >> 5; int ty = (int)pos2.Y >> 5; if (tx1 > tx) { tx1 = tx; } else if (tx2 < tx) { tx2 = tx; } if (ty1 > ty) { ty1 = ty; } else if (ty2 < ty) { ty2 = ty; } } #endif // ToDo: Remove this branching #if __ANDROID__ const int ActivateTileRange = 20; #else const int ActivateTileRange = 26; #endif tx1 -= ActivateTileRange; ty1 -= ActivateTileRange; tx2 += ActivateTileRange; ty2 += ActivateTileRange; for (int i = 0; i < actors.Count; i++) { if (actors[i].OnTileDeactivate(tx1 - 2, ty1 - 2, tx2 + 2, ty2 + 2)) { i--; } } eventMap.ActivateEvents(tx1, ty1, tx2, ty2, initState != InitState.Initializing); } eventMap.ProcessGenerators(timeMult); } ResolveCollisions(); // Ambient Light Transition if (ambientLightCurrent != ambientLightTarget) { float step = timeMult * 0.012f; if (MathF.Abs(ambientLightCurrent - ambientLightTarget) < step) { ambientLightCurrent = ambientLightTarget; } else { ambientLightCurrent += step * ((ambientLightTarget < ambientLightCurrent) ? -1 : 1); } } // Weather if (weatherType != WeatherType.None && commonResources.Graphics != null) { // ToDo: Apply weather effect to all other cameras too Vector3 viewPos = cameras[0].Transform.Pos; for (int i = 0; i < weatherIntensity; i++) { TileMap.DebrisCollisionAction collisionAction; if (weatherOutdoors) { collisionAction = TileMap.DebrisCollisionAction.Disappear; } else { collisionAction = (MathF.Rnd.NextFloat() > 0.7f ? TileMap.DebrisCollisionAction.None : TileMap.DebrisCollisionAction.Disappear); } Vector3 debrisPos = viewPos + MathF.Rnd.NextVector3((LevelRenderSetup.TargetSize.X / -2) - 40, (LevelRenderSetup.TargetSize.Y * -2 / 3), MainPlaneZ, LevelRenderSetup.TargetSize.X + 120, LevelRenderSetup.TargetSize.Y, 0); if (weatherType == WeatherType.Rain) { GraphicResource res = commonResources.Graphics["Rain"]; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float scale = MathF.Rnd.NextFloat(0.4f, 1.1f); float speedX = MathF.Rnd.NextFloat(2.2f, 2.7f) * scale; float speedY = MathF.Rnd.NextFloat(7.6f, 8.6f) * scale; debrisPos.Z = MainPlaneZ * scale; tileMap.CreateDebris(new TileMap.DestructibleDebris { Pos = debrisPos, Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, speedY), Scale = scale, Angle = MathF.Atan2(speedY, speedX), Alpha = 1f, Time = 180f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = collisionAction }); } else { GraphicResource res = commonResources.Graphics["Snow"]; Material material = res.Material.Res; Texture texture = material.MainTexture.Res; float scale = MathF.Rnd.NextFloat(0.4f, 1.1f); float speedX = MathF.Rnd.NextFloat(-1.6f, -1.2f) * scale; float speedY = MathF.Rnd.NextFloat(3f, 4f) * scale; float accel = MathF.Rnd.NextFloat(-0.008f, 0.008f) * scale; debrisPos.Z = MainPlaneZ * scale; tileMap.CreateDebris(new TileMap.DestructibleDebris { Pos = debrisPos, Size = res.Base.FrameDimensions, Speed = new Vector2(speedX, speedY), Acceleration = new Vector2(accel, -MathF.Abs(accel)), Scale = scale, Angle = MathF.Rnd.NextFloat(MathF.TwoPi), AngleSpeed = speedX * 0.02f, Alpha = 1f, Time = 180f, Material = material, MaterialOffset = texture.LookupAtlas(res.FrameOffset + MathF.Rnd.Next(res.FrameCount)), CollisionAction = collisionAction }); } } } // Active Boss if (activeBoss != null && activeBoss.Scene == null) { activeBoss = null; Hud hud = rootObject.GetComponent <Hud>(); if (hud != null) { hud.ActiveBoss = null; } InitLevelChange(ExitType.Normal, null); levelChangeTimer = 300; } if (initState == InitState.Initializing) { initState = InitState.Initialized; } collisionsCountA = 0; collisionsCountB = 0; collisionsCountC = 0; }